diff --git a/camera/device/3.4/default/CameraDeviceSession.cpp b/camera/device/3.4/default/CameraDeviceSession.cpp index bb4886d55d..b032357676 100644 --- a/camera/device/3.4/default/CameraDeviceSession.cpp +++ b/camera/device/3.4/default/CameraDeviceSession.cpp @@ -107,7 +107,6 @@ Return CameraDeviceSession::configureStreams_3_4( const camera_metadata_t *paramBuffer = nullptr; if (0 < requestedConfiguration.sessionParams.size()) { - ::android::hardware::camera::common::V1_0::helper::CameraMetadata sessionParams; V3_2::implementation::convertFromHidl(requestedConfiguration.sessionParams, ¶mBuffer); } diff --git a/camera/device/3.4/default/ExternalCameraDevice.cpp b/camera/device/3.4/default/ExternalCameraDevice.cpp index 14f82bcf1a..9a02ce86b4 100644 --- a/camera/device/3.4/default/ExternalCameraDevice.cpp +++ b/camera/device/3.4/default/ExternalCameraDevice.cpp @@ -638,12 +638,6 @@ status_t ExternalCameraDevice::initOutputCharsKeys(int fd, } } - // The document in aeAvailableTargetFpsRanges section says the minFps should - // not be larger than 15. - // We cannot support fixed 30fps but Android requires (min, max) and - // (max, max) ranges. - // TODO: populate more, right now this does not support 30,30 if the device - // has higher than 30 fps modes std::vector fpsRanges; // Variable range fpsRanges.push_back(minFps); @@ -693,7 +687,7 @@ status_t ExternalCameraDevice::initOutputCharsKeys(int fd, #undef UPDATE void ExternalCameraDevice::getFrameRateList( - int fd, float fpsUpperBound, SupportedV4L2Format* format) { + int fd, double fpsUpperBound, SupportedV4L2Format* format) { format->frameRates.clear(); v4l2_frmivalenum frameInterval { @@ -715,7 +709,7 @@ void ExternalCameraDevice::getFrameRateList( if (framerate > fpsUpperBound) { continue; } - ALOGI("index:%d, format:%c%c%c%c, w %d, h %d, framerate %f", + ALOGV("index:%d, format:%c%c%c%c, w %d, h %d, framerate %f", frameInterval.index, frameInterval.pixel_format & 0xFF, (frameInterval.pixel_format >> 8) & 0xFF, @@ -738,71 +732,68 @@ void ExternalCameraDevice::getFrameRateList( } } -CroppingType ExternalCameraDevice::initCroppingType( - /*inout*/std::vector* pSortedFmts) { - std::vector& sortedFmts = *pSortedFmts; +void ExternalCameraDevice::trimSupportedFormats( + CroppingType cropType, + /*inout*/std::vector* pFmts) { + std::vector& sortedFmts = *pFmts; + if (cropType == VERTICAL) { + std::sort(sortedFmts.begin(), sortedFmts.end(), + [](const SupportedV4L2Format& a, const SupportedV4L2Format& b) -> bool { + if (a.width == b.width) { + return a.height < b.height; + } + return a.width < b.width; + }); + } else { + std::sort(sortedFmts.begin(), sortedFmts.end(), + [](const SupportedV4L2Format& a, const SupportedV4L2Format& b) -> bool { + if (a.height == b.height) { + return a.width < b.width; + } + return a.height < b.height; + }); + } + + if (sortedFmts.size() == 0) { + ALOGE("%s: input format list is empty!", __FUNCTION__); + return; + } + const auto& maxSize = sortedFmts[sortedFmts.size() - 1]; float maxSizeAr = ASPECT_RATIO(maxSize); - float minAr = kMaxAspectRatio; - float maxAr = kMinAspectRatio; + + // Remove formats that has aspect ratio not croppable from largest size + std::vector out; for (const auto& fmt : sortedFmts) { float ar = ASPECT_RATIO(fmt); - if (ar < minAr) { - minAr = ar; - } - if (ar > maxAr) { - maxAr = ar; - } - } - - CroppingType ct = VERTICAL; - if (isAspectRatioClose(maxSizeAr, maxAr)) { - // Ex: 16:9 sensor, cropping horizontally to get to 4:3 - ct = HORIZONTAL; - } else if (isAspectRatioClose(maxSizeAr, minAr)) { - // Ex: 4:3 sensor, cropping vertically to get to 16:9 - ct = VERTICAL; - } else { - ALOGI("%s: camera maxSizeAr %f is not close to minAr %f or maxAr %f", - __FUNCTION__, maxSizeAr, minAr, maxAr); - if ((maxSizeAr - minAr) < (maxAr - maxSizeAr)) { - ct = VERTICAL; + if (isAspectRatioClose(ar, maxSizeAr)) { + out.push_back(fmt); + } else if (cropType == HORIZONTAL && ar < maxSizeAr) { + out.push_back(fmt); + } else if (cropType == VERTICAL && ar > maxSizeAr) { + out.push_back(fmt); } else { - ct = HORIZONTAL; + ALOGV("%s: size (%d,%d) is removed due to unable to crop %s from (%d,%d)", + __FUNCTION__, fmt.width, fmt.height, + cropType == VERTICAL ? "vertically" : "horizontally", + maxSize.width, maxSize.height); } - - // Remove formats that has aspect ratio not croppable from largest size - std::vector out; - for (const auto& fmt : sortedFmts) { - float ar = ASPECT_RATIO(fmt); - if (isAspectRatioClose(ar, maxSizeAr)) { - out.push_back(fmt); - } else if (ct == HORIZONTAL && ar < maxSizeAr) { - out.push_back(fmt); - } else if (ct == VERTICAL && ar > maxSizeAr) { - out.push_back(fmt); - } else { - ALOGD("%s: size (%d,%d) is removed due to unable to crop %s from (%d,%d)", - __FUNCTION__, fmt.width, fmt.height, - ct == VERTICAL ? "vertically" : "horizontally", - maxSize.width, maxSize.height); - } - } - sortedFmts = out; } - ALOGI("%s: camera croppingType is %s", __FUNCTION__, - ct == VERTICAL ? "VERTICAL" : "HORIZONTAL"); - return ct; + sortedFmts = out; } -void ExternalCameraDevice::initSupportedFormatsLocked(int fd) { +std::vector +ExternalCameraDevice::getCandidateSupportedFormatsLocked( + int fd, CroppingType cropType, + const std::vector& fpsLimits) { + std::vector outFmts; struct v4l2_fmtdesc fmtdesc { .index = 0, .type = V4L2_BUF_TYPE_VIDEO_CAPTURE}; int ret = 0; while (ret == 0) { ret = TEMP_FAILURE_RETRY(ioctl(fd, VIDIOC_ENUM_FMT, &fmtdesc)); - ALOGD("index:%d,ret:%d, format:%c%c%c%c", fmtdesc.index, ret, + ALOGV("index:%d,ret:%d, format:%c%c%c%c", fmtdesc.index, ret, fmtdesc.pixelformat & 0xFF, (fmtdesc.pixelformat >> 8) & 0xFF, (fmtdesc.pixelformat >> 16) & 0xFF, @@ -835,13 +826,20 @@ void ExternalCameraDevice::initSupportedFormatsLocked(int fd) { .fourcc = fmtdesc.pixelformat }; - float fpsUpperBound = -1.0; - for (const auto& limit : mCfg.fpsLimits) { - if (format.width <= limit.size.width && - format.height <= limit.size.height) { - fpsUpperBound = limit.fpsUpperBound; - break; + double fpsUpperBound = -1.0; + for (const auto& limit : fpsLimits) { + if (cropType == VERTICAL) { + if (format.width <= limit.size.width) { + fpsUpperBound = limit.fpsUpperBound; + break; + } + } else { // HORIZONTAL + if (format.height <= limit.size.height) { + fpsUpperBound = limit.fpsUpperBound; + break; + } } + } if (fpsUpperBound < 0.f) { continue; @@ -849,7 +847,7 @@ void ExternalCameraDevice::initSupportedFormatsLocked(int fd) { getFrameRateList(fd, fpsUpperBound, &format); if (!format.frameRates.empty()) { - mSupportedFormats.push_back(format); + outFmts.push_back(format); } } } @@ -857,16 +855,66 @@ void ExternalCameraDevice::initSupportedFormatsLocked(int fd) { } fmtdesc.index++; } + trimSupportedFormats(cropType, &outFmts); + return outFmts; +} - std::sort(mSupportedFormats.begin(), mSupportedFormats.end(), - [](const SupportedV4L2Format& a, const SupportedV4L2Format& b) -> bool { - if (a.width == b.width) { - return a.height < b.height; - } - return a.width < b.width; - }); +void ExternalCameraDevice::initSupportedFormatsLocked(int fd) { - mCroppingType = initCroppingType(&mSupportedFormats); + std::vector horizontalFmts = + getCandidateSupportedFormatsLocked(fd, HORIZONTAL, mCfg.fpsLimits); + std::vector verticalFmts = + getCandidateSupportedFormatsLocked(fd, VERTICAL, mCfg.fpsLimits); + + size_t horiSize = horizontalFmts.size(); + size_t vertSize = verticalFmts.size(); + + if (horiSize == 0 && vertSize == 0) { + ALOGE("%s: cannot find suitable cropping type!", __FUNCTION__); + return; + } + + if (horiSize == 0) { + mSupportedFormats = verticalFmts; + mCroppingType = VERTICAL; + return; + } else if (vertSize == 0) { + mSupportedFormats = horizontalFmts; + mCroppingType = HORIZONTAL; + return; + } + + const auto& maxHoriSize = horizontalFmts[horizontalFmts.size() - 1]; + const auto& maxVertSize = verticalFmts[verticalFmts.size() - 1]; + + // Try to keep largest possible output size + // When they are the same or ambiguous, pick the one support more sizes + if (maxHoriSize.width == maxVertSize.width && + maxHoriSize.height == maxVertSize.height) { + if (horiSize > vertSize) { + mSupportedFormats = horizontalFmts; + mCroppingType = HORIZONTAL; + } else { + mSupportedFormats = verticalFmts; + mCroppingType = VERTICAL; + } + } else if (maxHoriSize.width >= maxVertSize.width && + maxHoriSize.height >= maxVertSize.height) { + mSupportedFormats = horizontalFmts; + mCroppingType = HORIZONTAL; + } else if (maxHoriSize.width <= maxVertSize.width && + maxHoriSize.height <= maxVertSize.height) { + mSupportedFormats = verticalFmts; + mCroppingType = VERTICAL; + } else { + if (horiSize > vertSize) { + mSupportedFormats = horizontalFmts; + mCroppingType = HORIZONTAL; + } else { + mSupportedFormats = verticalFmts; + mCroppingType = VERTICAL; + } + } } } // namespace implementation diff --git a/camera/device/3.4/default/ExternalCameraDeviceSession.cpp b/camera/device/3.4/default/ExternalCameraDeviceSession.cpp index 5346f80399..01d7371b81 100644 --- a/camera/device/3.4/default/ExternalCameraDeviceSession.cpp +++ b/camera/device/3.4/default/ExternalCameraDeviceSession.cpp @@ -160,7 +160,6 @@ void ExternalCameraDeviceSession::dumpState(const native_handle_t* handle) { SupportedV4L2Format streamingFmt; std::unordered_set inflightFrames; { - Mutex::Autolock _l(mLock); bool sessionLocked = tryLock(mLock); if (!sessionLocked) { dprintf(fd, "!! ExternalCameraDeviceSession mLock may be deadlocked !!\n"); @@ -180,12 +179,13 @@ void ExternalCameraDeviceSession::dumpState(const native_handle_t* handle) { streaming ? "streaming" : "not streaming"); if (streaming) { // TODO: dump fps later - dprintf(fd, "Current V4L2 format %c%c%c%c %dx%d\n", + dprintf(fd, "Current V4L2 format %c%c%c%c %dx%d @ %ffps\n", streamingFmt.fourcc & 0xFF, (streamingFmt.fourcc >> 8) & 0xFF, (streamingFmt.fourcc >> 16) & 0xFF, (streamingFmt.fourcc >> 24) & 0xFF, - streamingFmt.width, streamingFmt.height); + streamingFmt.width, streamingFmt.height, + mV4l2StreamingFps); size_t numDequeuedV4l2Buffers = 0; { @@ -291,7 +291,6 @@ Return ExternalCameraDeviceSession::configureStreams_3_4( config_v32.streams[i] = requestedConfiguration.streams[i].v3_2; } - // Ignore requestedConfiguration.sessionParams. External camera does not support it Status status = configureStreams(config_v32, &outStreams_v33); V3_4::HalStreamConfiguration outStreams; @@ -451,6 +450,23 @@ void ExternalCameraDeviceSession::cleanupInflightFences( } } +int ExternalCameraDeviceSession::waitForV4L2BufferReturnLocked(std::unique_lock& lk) { + std::chrono::seconds timeout = std::chrono::seconds(kBufferWaitTimeoutSec); + mLock.unlock(); + auto st = mV4L2BufferReturned.wait_for(lk, timeout); + // Here we introduce a order where mV4l2BufferLock is acquired before mLock, while + // the normal lock acquisition order is reversed. This is fine because in most of + // cases we are protected by mInterfaceLock. The only thread that can cause deadlock + // is the OutputThread, where we do need to make sure we don't acquire mLock then + // mV4l2BufferLock + mLock.lock(); + if (st == std::cv_status::timeout) { + ALOGE("%s: wait for V4L2 buffer return timeout!", __FUNCTION__); + return -1; + } + return 0; +} + Status ExternalCameraDeviceSession::processOneCaptureRequest(const CaptureRequest& request) { Status status = initStatus(); if (status != Status::OK) { @@ -510,15 +526,59 @@ Status ExternalCameraDeviceSession::processOneCaptureRequest(const CaptureReques return Status::ILLEGAL_ARGUMENT; } + camera_metadata_entry fpsRange = mLatestReqSetting.find(ANDROID_CONTROL_AE_TARGET_FPS_RANGE); + if (fpsRange.count == 2) { + double requestFpsMax = fpsRange.data.i32[1]; + double closestFps = 0.0; + double fpsError = 1000.0; + bool fpsSupported = false; + for (const auto& fr : mV4l2StreamingFmt.frameRates) { + double f = fr.getDouble(); + if (std::fabs(requestFpsMax - f) < 1.0) { + fpsSupported = true; + break; + } + if (std::fabs(requestFpsMax - f) < fpsError) { + fpsError = std::fabs(requestFpsMax - f); + closestFps = f; + } + } + if (!fpsSupported) { + /* This can happen in a few scenarios: + * 1. The application is sending a FPS range not supported by the configured outputs. + * 2. The application is sending a valid FPS range for all cofigured outputs, but + * the selected V4L2 size can only run at slower speed. This should be very rare + * though: for this to happen a sensor needs to support at least 3 different aspect + * ratio outputs, and when (at least) two outputs are both not the main aspect ratio + * of the webcam, a third size that's larger might be picked and runs into this + * issue. + */ + ALOGW("%s: cannot reach fps %d! Will do %f instead", + __FUNCTION__, fpsRange.data.i32[1], closestFps); + requestFpsMax = closestFps; + } + + if (requestFpsMax != mV4l2StreamingFps) { + { + std::unique_lock lk(mV4l2BufferLock); + while (mNumDequeuedV4l2Buffers != 0) { + // Wait until pipeline is idle before reconfigure stream + int waitRet = waitForV4L2BufferReturnLocked(lk); + if (waitRet != 0) { + ALOGE("%s: wait for pipeline idle failed!", __FUNCTION__); + return Status::INTERNAL_ERROR; + } + } + } + configureV4l2StreamLocked(mV4l2StreamingFmt, requestFpsMax); + } + } + status = importRequest(request, allBufPtrs, allFences); if (status != Status::OK) { return status; } - // TODO: program fps range per capture request here - // or limit the set of availableFpsRange - - nsecs_t shutterTs = 0; sp frameIn = dequeueV4l2FrameLocked(&shutterTs); if ( frameIn == nullptr) { @@ -1979,7 +2039,46 @@ int ExternalCameraDeviceSession::v4l2StreamOffLocked() { return OK; } -int ExternalCameraDeviceSession::configureV4l2StreamLocked(const SupportedV4L2Format& v4l2Fmt) { +int ExternalCameraDeviceSession::setV4l2FpsLocked(double fps) { + // VIDIOC_G_PARM/VIDIOC_S_PARM: set fps + v4l2_streamparm streamparm = { .type = V4L2_BUF_TYPE_VIDEO_CAPTURE }; + // The following line checks that the driver knows about framerate get/set. + int ret = TEMP_FAILURE_RETRY(ioctl(mV4l2Fd.get(), VIDIOC_G_PARM, &streamparm)); + if (ret != 0) { + if (errno == -EINVAL) { + ALOGW("%s: device does not support VIDIOC_G_PARM", __FUNCTION__); + } + return -errno; + } + // Now check if the device is able to accept a capture framerate set. + if (!(streamparm.parm.capture.capability & V4L2_CAP_TIMEPERFRAME)) { + ALOGW("%s: device does not support V4L2_CAP_TIMEPERFRAME", __FUNCTION__); + return -EINVAL; + } + + // fps is float, approximate by a fraction. + const int kFrameRatePrecision = 10000; + streamparm.parm.capture.timeperframe.numerator = kFrameRatePrecision; + streamparm.parm.capture.timeperframe.denominator = + (fps * kFrameRatePrecision); + + if (TEMP_FAILURE_RETRY(ioctl(mV4l2Fd.get(), VIDIOC_S_PARM, &streamparm)) < 0) { + ALOGE("%s: failed to set framerate to %f: %s", __FUNCTION__, fps, strerror(errno)); + return -1; + } + + double retFps = streamparm.parm.capture.timeperframe.denominator / + static_cast(streamparm.parm.capture.timeperframe.numerator); + if (std::fabs(fps - retFps) > 1.0) { + ALOGE("%s: expect fps %f, got %f instead", __FUNCTION__, fps, retFps); + return -1; + } + mV4l2StreamingFps = fps; + return 0; +} + +int ExternalCameraDeviceSession::configureV4l2StreamLocked( + const SupportedV4L2Format& v4l2Fmt, double requestFps) { int ret = v4l2StreamOffLocked(); if (ret != OK) { ALOGE("%s: stop v4l2 streaming failed: ret %d", __FUNCTION__, ret); @@ -2016,46 +2115,31 @@ int ExternalCameraDeviceSession::configureV4l2StreamLocked(const SupportedV4L2Fo uint32_t bufferSize = fmt.fmt.pix.sizeimage; ALOGI("%s: V4L2 buffer size is %d", __FUNCTION__, bufferSize); - float maxFps = -1.f; - float fps = 1000.f; - const float kDefaultFps = 30.f; - // Try to pick the slowest fps that is at least 30 - for (const auto& fr : v4l2Fmt.frameRates) { - double f = fr.getDouble(); - if (maxFps < f) { - maxFps = f; - } - if (f >= kDefaultFps && f < fps) { - fps = f; - } - } - if (fps == 1000.f) { - fps = maxFps; - } - - // VIDIOC_G_PARM/VIDIOC_S_PARM: set fps - v4l2_streamparm streamparm = { .type = V4L2_BUF_TYPE_VIDEO_CAPTURE }; - // The following line checks that the driver knows about framerate get/set. - if (TEMP_FAILURE_RETRY(ioctl(mV4l2Fd.get(), VIDIOC_G_PARM, &streamparm)) >= 0) { - // Now check if the device is able to accept a capture framerate set. - if (streamparm.parm.capture.capability & V4L2_CAP_TIMEPERFRAME) { - // |frame_rate| is float, approximate by a fraction. - const int kFrameRatePrecision = 10000; - streamparm.parm.capture.timeperframe.numerator = kFrameRatePrecision; - streamparm.parm.capture.timeperframe.denominator = - (fps * kFrameRatePrecision); - - if (TEMP_FAILURE_RETRY(ioctl(mV4l2Fd.get(), VIDIOC_S_PARM, &streamparm)) < 0) { - ALOGE("%s: failed to set framerate to %f", __FUNCTION__, fps); - return UNKNOWN_ERROR; + const double kDefaultFps = 30.0; + double fps = 1000.0; + if (requestFps != 0.0) { + fps = requestFps; + } else { + double maxFps = -1.0; + // Try to pick the slowest fps that is at least 30 + for (const auto& fr : v4l2Fmt.frameRates) { + double f = fr.getDouble(); + if (maxFps < f) { + maxFps = f; + } + if (f >= kDefaultFps && f < fps) { + fps = f; } } + if (fps == 1000.0) { + fps = maxFps; + } } - float retFps = streamparm.parm.capture.timeperframe.denominator / - streamparm.parm.capture.timeperframe.numerator; - if (std::fabs(fps - retFps) > std::numeric_limits::epsilon()) { - ALOGE("%s: expect fps %f, got %f instead", __FUNCTION__, fps, retFps); - return BAD_VALUE; + + int fpsRet = setV4l2FpsLocked(fps); + if (fpsRet != 0 && fpsRet != -EINVAL) { + ALOGE("%s: set fps failed: %s", __FUNCTION__, strerror(fpsRet)); + return fpsRet; } uint32_t v4lBufferCount = (fps >= kDefaultFps) ? @@ -2136,17 +2220,8 @@ sp ExternalCameraDeviceSession::dequeueV4l2FrameLocked(/*out*/nsecs_t { std::unique_lock lk(mV4l2BufferLock); if (mNumDequeuedV4l2Buffers == mV4L2BufferCount) { - std::chrono::seconds timeout = std::chrono::seconds(kBufferWaitTimeoutSec); - mLock.unlock(); - auto st = mV4L2BufferReturned.wait_for(lk, timeout); - // Here we introduce a case where mV4l2BufferLock is acquired before mLock, while - // the normal lock acquisition order is reversed, but this is fine because in most of - // cases we are protected by mInterfaceLock. The only thread that can compete these - // locks are the OutputThread, where we do need to make sure we don't acquire mLock then - // mV4l2BufferLock - mLock.lock(); - if (st == std::cv_status::timeout) { - ALOGE("%s: wait for V4L2 buffer return timeout!", __FUNCTION__); + int waitRet = waitForV4L2BufferReturnLocked(lk); + if (waitRet != 0) { return ret; } } 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 9c0ad7f576..53150970e9 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 @@ -177,8 +177,11 @@ protected: status_t initDefaultRequests(); status_t fillCaptureResult(common::V1_0::helper::CameraMetadata& md, nsecs_t timestamp); Status configureStreams(const V3_2::StreamConfiguration&, V3_3::HalStreamConfiguration* out); - int configureV4l2StreamLocked(const SupportedV4L2Format& fmt); + // fps = 0.0 means default, which is + // slowest fps that is at least 30, or fastest fps if 30 is not supported + int configureV4l2StreamLocked(const SupportedV4L2Format& fmt, double fps = 0.0); int v4l2StreamOffLocked(); + int setV4l2FpsLocked(double fps); // TODO: change to unique_ptr for better tracking sp dequeueV4l2FrameLocked(/*out*/nsecs_t* shutterTs); // Called with mLock hold @@ -212,6 +215,8 @@ protected: ssize_t getJpegBufferSize(uint32_t width, uint32_t height) const; + int waitForV4L2BufferReturnLocked(std::unique_lock& lk); + class OutputThread : public android::Thread { public: OutputThread(wp parent, CroppingType); @@ -307,6 +312,7 @@ protected: bool mV4l2Streaming = false; SupportedV4L2Format mV4l2StreamingFmt; + double mV4l2StreamingFps = 0.0; size_t mV4L2BufferCount = 0; static const int kBufferWaitTimeoutSec = 3; // TODO: handle long exposure (or not allowing) 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 5880469d37..a52f0e4ccb 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 @@ -78,7 +78,6 @@ struct ExternalCameraDevice : public ICameraDevice { /* End of Methods from ::android::hardware::camera::device::V3_2::ICameraDevice */ protected: - void getFrameRateList(int fd, float fpsUpperBound, SupportedV4L2Format* format); // Init supported w/h/format/fps in mSupportedFormats. Caller still owns fd void initSupportedFormatsLocked(int fd); @@ -92,7 +91,15 @@ protected: status_t initOutputCharsKeys(int fd, ::android::hardware::camera::common::V1_0::helper::CameraMetadata*); - static CroppingType initCroppingType(/*inout*/std::vector*); + static void getFrameRateList(int fd, double fpsUpperBound, SupportedV4L2Format* format); + + // Get candidate supported formats list of input cropping type. + static std::vector getCandidateSupportedFormatsLocked( + int fd, CroppingType cropType, + const std::vector& fpsLimits); + // Trim supported format list by the cropping type. Also sort output formats by width/height + static void trimSupportedFormats(CroppingType cropType, + /*inout*/std::vector* pFmts); Mutex mLock; bool mInitFailed = false;