From 355d9c6b74cd22a88fc7d1c9ba2e928ba566c69e Mon Sep 17 00:00:00 2001 From: Yin-Chia Yeh Date: Tue, 24 Feb 2015 15:51:43 -0800 Subject: Camera2Client: handle slower jpeg stream sensor If largest jpeg stream cannot sustain 30 FPS, don't create jpeg stream until takePicture is called and remove it after still capture is done. Also, disable video snapshot for such sensors so video snapshot won't slow down video recording. Bug: 22231605 Change-Id: I2b34d2537c224694ae10f2006b5a46be45a1b1a6 --- .../camera/libcameraservice/api1/Camera2Client.cpp | 60 +++++++++++++--- .../camera/libcameraservice/api1/Camera2Client.h | 9 ++- .../api1/client2/CaptureSequencer.cpp | 11 +++ .../libcameraservice/api1/client2/Parameters.cpp | 79 ++++++++++++++++++++-- .../libcameraservice/api1/client2/Parameters.h | 13 ++++ 5 files changed, 154 insertions(+), 18 deletions(-) (limited to 'services/camera/libcameraservice/api1') diff --git a/services/camera/libcameraservice/api1/Camera2Client.cpp b/services/camera/libcameraservice/api1/Camera2Client.cpp index e109595..36e99dd 100644 --- a/services/camera/libcameraservice/api1/Camera2Client.cpp +++ b/services/camera/libcameraservice/api1/Camera2Client.cpp @@ -764,16 +764,22 @@ status_t Camera2Client::startPreviewL(Parameters ¶ms, bool restart) { // first capture latency on HAL3 devices, and potentially on some HAL2 // devices. So create it unconditionally at preview start. As a drawback, // this increases gralloc memory consumption for applications that don't - // ever take a picture. + // ever take a picture. Do not enter this mode when jpeg stream will slow + // down preview. // TODO: Find a better compromise, though this likely would involve HAL // changes. int lastJpegStreamId = mJpegProcessor->getStreamId(); - res = updateProcessorStream(mJpegProcessor, params); - if (res != OK) { - ALOGE("%s: Camera %d: Can't pre-configure still image " - "stream: %s (%d)", - __FUNCTION__, mCameraId, strerror(-res), res); - return res; + // If jpeg stream will slow down preview, make sure we remove it before starting preview + if (params.slowJpegMode) { + mJpegProcessor->deleteStream(); + } else { + res = updateProcessorStream(mJpegProcessor, params); + if (res != OK) { + ALOGE("%s: Camera %d: Can't pre-configure still image " + "stream: %s (%d)", + __FUNCTION__, mCameraId, strerror(-res), res); + return res; + } } bool jpegStreamChanged = mJpegProcessor->getStreamId() != lastJpegStreamId; @@ -1453,9 +1459,12 @@ status_t Camera2Client::takePicture(int msgType) { } ALOGV("%s: Camera %d: Starting picture capture", __FUNCTION__, mCameraId); - int lastJpegStreamId = mJpegProcessor->getStreamId(); - res = updateProcessorStream(mJpegProcessor, l.mParameters); + // slowJpegMode will create jpeg stream in CaptureSequencer before capturing + if (!l.mParameters.slowJpegMode) { + res = updateProcessorStream(mJpegProcessor, l.mParameters); + } + // If video snapshot fail to configureStream, try override video snapshot size to // video size if (res == BAD_VALUE && l.mParameters.state == Parameters::VIDEO_SNAPSHOT) { @@ -1943,6 +1952,39 @@ status_t Camera2Client::stopStream() { return mStreamingProcessor->stopStream(); } +status_t Camera2Client::createJpegStreamL(Parameters ¶ms) { + status_t res = OK; + int lastJpegStreamId = mJpegProcessor->getStreamId(); + if (lastJpegStreamId != NO_STREAM) { + return INVALID_OPERATION; + } + + res = mStreamingProcessor->togglePauseStream(/*pause*/true); + if (res != OK) { + ALOGE("%s: Camera %d: Can't pause streaming: %s (%d)", + __FUNCTION__, mCameraId, strerror(-res), res); + return res; + } + + res = mDevice->flush(); + if (res != OK) { + ALOGE("%s: Camera %d: Unable flush device: %s (%d)", + __FUNCTION__, mCameraId, strerror(-res), res); + return res; + } + + // Ideally we don't need this, but current camera device + // status tracking mechanism demands it. + res = mDevice->waitUntilDrained(); + if (res != OK) { + ALOGE("%s: Camera %d: Waiting device drain failed: %s (%d)", + __FUNCTION__, mCameraId, strerror(-res), res); + } + + res = updateProcessorStream(mJpegProcessor, params); + return res; +} + const int32_t Camera2Client::kPreviewRequestIdStart; const int32_t Camera2Client::kPreviewRequestIdEnd; const int32_t Camera2Client::kRecordingRequestIdStart; diff --git a/services/camera/libcameraservice/api1/Camera2Client.h b/services/camera/libcameraservice/api1/Camera2Client.h index c288313..d50bf63 100644 --- a/services/camera/libcameraservice/api1/Camera2Client.h +++ b/services/camera/libcameraservice/api1/Camera2Client.h @@ -129,6 +129,9 @@ public: status_t stopStream(); + // For the slowJpegMode to create jpeg stream when precapture sequence is done + status_t createJpegStreamL(camera2::Parameters ¶ms); + static size_t calculateBufferSize(int width, int height, int format, int stride); @@ -145,6 +148,9 @@ public: static const char* kAutofocusLabel; static const char* kTakepictureLabel; + // Used with stream IDs + static const int NO_STREAM = -1; + private: /** ICamera interface-related private members */ typedef camera2::Parameters Parameters; @@ -177,9 +183,6 @@ private: void setPreviewCallbackFlagL(Parameters ¶ms, int flag); status_t updateRequests(Parameters ¶ms); - // Used with stream IDs - static const int NO_STREAM = -1; - template status_t updateProcessorStream(sp processor, Parameters params); template getPreviewStreamId()); + + int captureStreamId = client->getCaptureStreamId(); + if (captureStreamId == Camera2Client::NO_STREAM) { + res = client->createJpegStreamL(l.mParameters); + if (res != OK || client->getCaptureStreamId() == Camera2Client::NO_STREAM) { + ALOGE("%s: Camera %d: cannot create jpeg stream for slowJpeg mode: %s (%d)", + __FUNCTION__, client->getCameraId(), strerror(-res), res); + return DONE; + } + } + outputStreams.push(client->getCaptureStreamId()); if (l.mParameters.previewCallbackFlags & diff --git a/services/camera/libcameraservice/api1/client2/Parameters.cpp b/services/camera/libcameraservice/api1/client2/Parameters.cpp index c3a6842..442eb75 100644 --- a/services/camera/libcameraservice/api1/client2/Parameters.cpp +++ b/services/camera/libcameraservice/api1/client2/Parameters.cpp @@ -889,15 +889,30 @@ status_t Parameters::initialize(const CameraMetadata *info, int deviceVersion) { previewCallbackOneShot = false; previewCallbackSurface = false; + Size maxJpegSize = getMaxSize(getAvailableJpegSizes()); + int64_t minFrameDurationNs = getJpegStreamMinFrameDurationNs(maxJpegSize); + + slowJpegMode = false; + if (minFrameDurationNs > kSlowJpegModeThreshold) { + slowJpegMode = true; + // Slow jpeg devices does not support video snapshot without + // slowing down preview. + // TODO: support video size video snapshot only? + params.set(CameraParameters::KEY_VIDEO_SNAPSHOT_SUPPORTED, + CameraParameters::FALSE); + } + char value[PROPERTY_VALUE_MAX]; property_get("camera.disable_zsl_mode", value, "0"); - if (!strcmp(value,"1")) { + if (!strcmp(value,"1") || slowJpegMode) { ALOGI("Camera %d: Disabling ZSL mode", cameraId); zslMode = false; } else { zslMode = true; } + ALOGI("%s: zslMode: %d slowJpegMode %d", __FUNCTION__, zslMode, slowJpegMode); + lightFx = LIGHTFX_NONE; state = STOPPED; @@ -2778,6 +2793,17 @@ Parameters::Size Parameters::getMaxSizeForRatio( return maxSize; } +Parameters::Size Parameters::getMaxSize(const Vector &sizes) { + Size maxSize = {-1, -1}; + for (size_t i = 0; i < sizes.size(); i++) { + if (sizes[i].width > maxSize.width || + (sizes[i].width == maxSize.width && sizes[i].height > maxSize.height )) { + maxSize = sizes[i]; + } + } + return maxSize; +} + Vector Parameters::getStreamConfigurations() { const int STREAM_CONFIGURATION_SIZE = 4; const int STREAM_FORMAT_OFFSET = 0; @@ -2792,7 +2818,7 @@ Vector Parameters::getStreamConfigurations() { camera_metadata_ro_entry_t availableStreamConfigs = staticInfo(ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS); - for (size_t i=0; i < availableStreamConfigs.count; i+= STREAM_CONFIGURATION_SIZE) { + for (size_t i = 0; i < availableStreamConfigs.count; i+= STREAM_CONFIGURATION_SIZE) { int32_t format = availableStreamConfigs.data.i32[i + STREAM_FORMAT_OFFSET]; int32_t width = availableStreamConfigs.data.i32[i + STREAM_WIDTH_OFFSET]; int32_t height = availableStreamConfigs.data.i32[i + STREAM_HEIGHT_OFFSET]; @@ -2803,11 +2829,52 @@ Vector Parameters::getStreamConfigurations() { return scs; } +int64_t Parameters::getJpegStreamMinFrameDurationNs(Parameters::Size size) { + if (mDeviceVersion >= CAMERA_DEVICE_API_VERSION_3_2) { + const int STREAM_DURATION_SIZE = 4; + const int STREAM_FORMAT_OFFSET = 0; + const int STREAM_WIDTH_OFFSET = 1; + const int STREAM_HEIGHT_OFFSET = 2; + const int STREAM_DURATION_OFFSET = 3; + camera_metadata_ro_entry_t availableStreamMinDurations = + staticInfo(ANDROID_SCALER_AVAILABLE_MIN_FRAME_DURATIONS); + for (size_t i = 0; i < availableStreamMinDurations.count; i+= STREAM_DURATION_SIZE) { + int64_t format = availableStreamMinDurations.data.i64[i + STREAM_FORMAT_OFFSET]; + int64_t width = availableStreamMinDurations.data.i64[i + STREAM_WIDTH_OFFSET]; + int64_t height = availableStreamMinDurations.data.i64[i + STREAM_HEIGHT_OFFSET]; + int64_t duration = availableStreamMinDurations.data.i64[i + STREAM_DURATION_OFFSET]; + if (format == HAL_PIXEL_FORMAT_BLOB && width == size.width && height == size.height) { + return duration; + } + } + } else { + Vector availableJpegSizes = getAvailableJpegSizes(); + size_t streamIdx = availableJpegSizes.size(); + for (size_t i = 0; i < availableJpegSizes.size(); i++) { + if (availableJpegSizes[i].width == size.width && + availableJpegSizes[i].height == size.height) { + streamIdx = i; + break; + } + } + if (streamIdx != availableJpegSizes.size()) { + camera_metadata_ro_entry_t jpegMinDurations = + staticInfo(ANDROID_SCALER_AVAILABLE_JPEG_MIN_DURATIONS); + if (streamIdx < jpegMinDurations.count) { + return jpegMinDurations.data.i64[streamIdx]; + } + } + } + ALOGE("%s: cannot find min frame duration for jpeg size %dx%d", + __FUNCTION__, size.width, size.height); + return -1; +} + SortedVector Parameters::getAvailableOutputFormats() { SortedVector outputFormats; // Non-duplicated output formats if (mDeviceVersion >= CAMERA_DEVICE_API_VERSION_3_2) { Vector scs = getStreamConfigurations(); - for (size_t i=0; i < scs.size(); i++) { + for (size_t i = 0; i < scs.size(); i++) { const StreamConfiguration &sc = scs[i]; if (sc.isInput == ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT) { outputFormats.add(sc.format); @@ -2815,7 +2882,7 @@ SortedVector Parameters::getAvailableOutputFormats() { } } else { camera_metadata_ro_entry_t availableFormats = staticInfo(ANDROID_SCALER_AVAILABLE_FORMATS); - for (size_t i=0; i < availableFormats.count; i++) { + for (size_t i = 0; i < availableFormats.count; i++) { outputFormats.add(availableFormats.data.i32[i]); } } @@ -2826,7 +2893,7 @@ Vector Parameters::getAvailableJpegSizes() { Vector jpegSizes; if (mDeviceVersion >= CAMERA_DEVICE_API_VERSION_3_2) { Vector scs = getStreamConfigurations(); - for (size_t i=0; i < scs.size(); i++) { + for (size_t i = 0; i < scs.size(); i++) { const StreamConfiguration &sc = scs[i]; if (sc.isInput == ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT && sc.format == HAL_PIXEL_FORMAT_BLOB) { @@ -2840,7 +2907,7 @@ Vector Parameters::getAvailableJpegSizes() { const int HEIGHT_OFFSET = 1; camera_metadata_ro_entry_t availableJpegSizes = staticInfo(ANDROID_SCALER_AVAILABLE_JPEG_SIZES); - for (size_t i=0; i < availableJpegSizes.count; i+= JPEG_SIZE_ENTRY_COUNT) { + for (size_t i = 0; i < availableJpegSizes.count; i+= JPEG_SIZE_ENTRY_COUNT) { int width = availableJpegSizes.data.i32[i + WIDTH_OFFSET]; int height = availableJpegSizes.data.i32[i + HEIGHT_OFFSET]; Size sz = {width, height}; diff --git a/services/camera/libcameraservice/api1/client2/Parameters.h b/services/camera/libcameraservice/api1/client2/Parameters.h index 46d48bc..972d007 100644 --- a/services/camera/libcameraservice/api1/client2/Parameters.h +++ b/services/camera/libcameraservice/api1/client2/Parameters.h @@ -166,6 +166,9 @@ struct Parameters { bool previewCallbackSurface; bool zslMode; + // Whether the jpeg stream is slower than 30FPS and can slow down preview. + // When slowJpegMode is true, zslMode must be false to avoid slowing down preview. + bool slowJpegMode; // Overall camera state enum State { @@ -190,6 +193,8 @@ struct Parameters { static const int MAX_INITIAL_PREVIEW_HEIGHT = 1080; // Aspect ratio tolerance static const CONSTEXPR float ASPECT_RATIO_TOLERANCE = 0.001; + // Threshold for slow jpeg mode + static const int64_t kSlowJpegModeThreshold = 33400000LL; // 33.4 ms // Full static camera info, object owned by someone else, such as // Camera2Device. @@ -377,15 +382,23 @@ private: int32_t height; int32_t isInput; }; + // Helper function extract available stream configuration // Only valid since device HAL version 3.2 // returns an empty Vector if device HAL version does support it Vector getStreamConfigurations(); + // Helper function to get minimum frame duration for a jpeg size + // return -1 if input jpeg size cannot be found in supported size list + int64_t getJpegStreamMinFrameDurationNs(Parameters::Size size); + // Helper function to get non-duplicated available output formats SortedVector getAvailableOutputFormats(); // Helper function to get available output jpeg sizes Vector getAvailableJpegSizes(); + // Helper function to get maximum size in input Size vector. + // The maximum size is defined by comparing width first, when width ties comparing height. + Size getMaxSize(const Vector& sizes); int mDeviceVersion; }; -- cgit v1.1