From dc89a99bddc9bb669fc1c8eabaf52633739fd5bd Mon Sep 17 00:00:00 2001 From: Sampath Vangaveti Date: Fri, 6 May 2016 16:09:12 +0530 Subject: [PATCH] QCamera2: HAL/HAL3: Convert Boottime from ISP to MONOTONIC Issue: Diplay freeze observed sometimes, if there is any suspend/resume of the device. The issue found to be with differences in the timesources used by display and camera for timestamp calculation. Fix: Measure the clock offset between BOOTTIME and MONOTONIC. The clock domain source for ISP is BOOTTIME and for display, it is MONOTONIC. The offset is used to convert from clock domain of camera to display. Added following set prop to switch between camera time sources. persist.camera.time.monotonic Default value is 1. value 0 indicates Boot time from camera. value 1 indicates Monotonic time from camera. Change-Id: I733aa17e89ccaa7f5ea6d2eae5e1cd6428c81a85 CRs-Fixed: 1005906 --- camera/QCamera2/HAL/QCamera2HWI.cpp | 51 ++++++++++++++- camera/QCamera2/HAL/QCamera2HWI.h | 5 +- camera/QCamera2/HAL/QCamera2HWICallbacks.cpp | 8 +++ camera/QCamera2/HAL3/QCamera3HWI.cpp | 65 +++++++++++++++++++- camera/QCamera2/HAL3/QCamera3HWI.h | 5 +- vendor_prop.mk | 2 +- 6 files changed, 129 insertions(+), 7 deletions(-) diff --git a/camera/QCamera2/HAL/QCamera2HWI.cpp b/camera/QCamera2/HAL/QCamera2HWI.cpp index 3199311..fd4f2f1 100644 --- a/camera/QCamera2/HAL/QCamera2HWI.cpp +++ b/camera/QCamera2/HAL/QCamera2HWI.cpp @@ -1671,7 +1671,8 @@ QCamera2HardwareInterface::QCamera2HardwareInterface(uint32_t cameraId) mMetadataMem(NULL), mCACDoneReceived(false), m_bNeedRestart(false), - mIgnoredPreviewCount(0) + mIgnoredPreviewCount(0), + mBootToMonoTimestampOffset(0) { #ifdef TARGET_TS_MAKEUP memset(&mFaceRect, -1, sizeof(mFaceRect)); @@ -1959,6 +1960,23 @@ int QCamera2HardwareInterface::openCamera() pthread_mutex_unlock(&gCamLock); } + // Setprop to decide the time source (whether boottime or monotonic). + // By default, use monotonic time. + property_get("persist.camera.time.monotonic", value, "1"); + mBootToMonoTimestampOffset = 0; + if (atoi(value) == 1) { + // if monotonic is set, then need to use time in monotonic. + // So, Measure the clock offset between BOOTTIME and MONOTONIC + // The clock domain source for ISP is BOOTTIME and + // for display is MONOTONIC + // The below offset is used to convert from clock domain of other subsystem + // (hardware composer) to that of camera. Assumption is that this + // offset won't change during the life cycle of the camera device. In other + // words, camera device shouldn't be open during CPU suspend. + mBootToMonoTimestampOffset = getBootToMonoTimeOffset(); + } + LOGH("mBootToMonoTimestampOffset = %lld", mBootToMonoTimestampOffset); + return NO_ERROR; error_exit3: @@ -10075,4 +10093,35 @@ bool QCamera2HardwareInterface::isLowPowerMode() return isLowpower; } +/*=========================================================================== + * FUNCTION : getBootToMonoTimeOffset + * + * DESCRIPTION: Calculate offset that is used to convert from + * clock domain of boot to monotonic + * + * PARAMETERS : + * None + * + * RETURN : clock offset between boottime and monotonic time. + * + *==========================================================================*/ +nsecs_t QCamera2HardwareInterface::getBootToMonoTimeOffset() +{ + // try three times to get the clock offset, choose the one + // with the minimum gap in measurements. + const int tries = 3; + nsecs_t bestGap, measured; + for (int i = 0; i < tries; ++i) { + const nsecs_t tmono = systemTime(SYSTEM_TIME_MONOTONIC); + const nsecs_t tbase = systemTime(SYSTEM_TIME_BOOTTIME); + const nsecs_t tmono2 = systemTime(SYSTEM_TIME_MONOTONIC); + const nsecs_t gap = tmono2 - tmono; + if (i == 0 || gap < bestGap) { + bestGap = gap; + measured = tbase - ((tmono + tmono2) >> 1); + } + } + return measured; +} + }; // namespace qcamera diff --git a/camera/QCamera2/HAL/QCamera2HWI.h b/camera/QCamera2/HAL/QCamera2HWI.h index 739cba1..9c1506f 100644 --- a/camera/QCamera2/HAL/QCamera2HWI.h +++ b/camera/QCamera2/HAL/QCamera2HWI.h @@ -382,6 +382,7 @@ private: QCameraExif *getExifData(); cam_sensor_t getSensorType(); bool isLowPowerMode(); + nsecs_t getBootToMonoTimeOffset(); int32_t processAutoFocusEvent(cam_auto_focus_data_t &focus_data); int32_t processZoomEvent(cam_crop_data_t &crop_info); @@ -765,7 +766,9 @@ private: Mutex mMapLock; Condition mMapCond; // Count to determine the number of preview frames ignored for displaying. - uint8_t mIgnoredPreviewCount; + uint8_t mIgnoredPreviewCount; + //The offset between BOOTTIME and MONOTONIC timestamps + nsecs_t mBootToMonoTimestampOffset; }; }; // namespace qcamera diff --git a/camera/QCamera2/HAL/QCamera2HWICallbacks.cpp b/camera/QCamera2/HAL/QCamera2HWICallbacks.cpp index 5308df5..7c59bff 100644 --- a/camera/QCamera2/HAL/QCamera2HWICallbacks.cpp +++ b/camera/QCamera2/HAL/QCamera2HWICallbacks.cpp @@ -734,6 +734,9 @@ void QCamera2HardwareInterface::synchronous_stream_cb_routine( } frameTime = nsecs_t(frame->ts.tv_sec) * 1000000000LL + frame->ts.tv_nsec; + // Convert Boottime from camera to Monotime for display if needed. + // Otherwise, mBootToMonoTimestampOffset value will be 0. + frameTime = frameTime - pme->mBootToMonoTimestampOffset; // Calculate the future presentation time stamp for displaying frames at regular interval //mPreviewTimestamp = pme->mCameraDisplay.computePresentationTimeStamp(frameTime); stream->mStreamTimestamp = frameTime; @@ -1538,6 +1541,11 @@ void QCamera2HardwareInterface::video_stream_cb_routine(mm_camera_super_buf_t *s cbArg.cb_type = QCAMERA_DATA_TIMESTAMP_CALLBACK; cbArg.msg_type = CAMERA_MSG_VIDEO_FRAME; cbArg.data = video_mem; + + // Convert Boottime from camera to Monotime for video if needed. + // Otherwise, mBootToMonoTimestampOffset value will be 0. + timeStamp = timeStamp - pme->mBootToMonoTimestampOffset; + LOGD("Final video buffer TimeStamp : %lld ", timeStamp); cbArg.timestamp = timeStamp; int32_t rc = pme->m_cbNotifier.notifyCallback(cbArg); if (rc != NO_ERROR) { diff --git a/camera/QCamera2/HAL3/QCamera3HWI.cpp b/camera/QCamera2/HAL3/QCamera3HWI.cpp index ebb58f4..61e40cc 100644 --- a/camera/QCamera2/HAL3/QCamera3HWI.cpp +++ b/camera/QCamera2/HAL3/QCamera3HWI.cpp @@ -63,6 +63,8 @@ namespace qcamera { #define DATA_PTR(MEM_OBJ,INDEX) MEM_OBJ->getPtr( INDEX ) +#define TIME_SOURCE ANDROID_SENSOR_INFO_TIMESTAMP_SOURCE_UNKNOWN + #define EMPTY_PIPELINE_DELAY 2 #define PARTIAL_RESULT_COUNT 2 #define FRAME_SKIP_DELAY 0 @@ -361,7 +363,9 @@ QCamera3HardwareInterface::QCamera3HardwareInterface(uint32_t cameraId, mLdafCalibExist(false), mPowerHintEnabled(false), mLastCustIntentFrmNum(-1), - mState(CLOSED) + mState(CLOSED), + mBootToMonoTimestampOffset(0), + mUseAVTimer(false) { getLogLevel(); m_perfLock.lock_init(); @@ -730,6 +734,23 @@ int QCamera3HardwareInterface::openCamera() pthread_mutex_unlock(&gCamLock); } + // Setprop to decide the time source (whether boottime or monotonic). + // By default, use monotonic time. + property_get("persist.camera.time.monotonic", value, "1"); + mBootToMonoTimestampOffset = 0; + if (atoi(value) == 1) { + // if monotonic is set, then need to use time in monotonic. + // So, Measure the clock offset between BOOTTIME and MONOTONIC + // The clock domain source for ISP is BOOTTIME and + // for display is MONOTONIC + // The below offset is used to convert from clock domain of other subsystem + // (hardware composer) to that of camera. Assumption is that this + // offset won't change during the life cycle of the camera device. In other + // words, camera device shouldn't be open during CPU suspend. + mBootToMonoTimestampOffset = getBootToMonoTimeOffset(); + } + LOGH("mBootToMonoTimestampOffset = %lld", mBootToMonoTimestampOffset); + return NO_ERROR; } @@ -2615,6 +2636,12 @@ void QCamera3HardwareInterface::handleMetadataWithLock( uint32_t frame_number, urgent_frame_number; int64_t capture_time; + // Convert Boottime from camera to Monotime except for VT usecase where AVTimer is used. + uint8_t timestampSource = TIME_SOURCE; + nsecs_t timeOffset = mBootToMonoTimestampOffset; + if (mUseAVTimer || (ANDROID_SENSOR_INFO_TIMESTAMP_SOURCE_UNKNOWN != timestampSource)) + timeOffset = 0; + int32_t *p_frame_number_valid = POINTER_OF_META(CAM_INTF_META_FRAME_NUMBER_VALID, metadata); uint32_t *p_frame_number = POINTER_OF_META(CAM_INTF_META_FRAME_NUMBER, metadata); @@ -2640,7 +2667,7 @@ void QCamera3HardwareInterface::handleMetadataWithLock( } else { frame_number_valid = *p_frame_number_valid; frame_number = *p_frame_number; - capture_time = *p_capture_time; + capture_time = *p_capture_time - timeOffset; urgent_frame_number_valid = *p_urgent_frame_number_valid; urgent_frame_number = *p_urgent_frame_number; } @@ -3367,6 +3394,7 @@ int QCamera3HardwareInterface::processCaptureRequest( LOGE("Failed to disable CDS for HFR mode"); } + setMobicat(); /* Set fps and hfr mode while sending meta stream info so that sensor @@ -6258,7 +6286,7 @@ int QCamera3HardwareInterface::initStaticMetadata(uint32_t cameraId) staticInfo.update(ANDROID_TONEMAP_MAX_CURVE_POINTS, &gCamCapability[cameraId]->max_tone_map_curve_points, 1); - uint8_t timestampSource = ANDROID_SENSOR_INFO_TIMESTAMP_SOURCE_UNKNOWN; + uint8_t timestampSource = TIME_SOURCE; staticInfo.update(ANDROID_SENSOR_INFO_TIMESTAMP_SOURCE, ×tampSource, 1); @@ -10109,4 +10137,35 @@ int32_t QCamera3HardwareInterface::setBundleInfo() return rc; } +/*=========================================================================== + * FUNCTION : getBootToMonoTimeOffset + * + * DESCRIPTION: Calculate offset that is used to convert from + * clock domain of boot to monotonic + * + * PARAMETERS : + * None + * + * RETURN : clock offset between boottime and monotonic time. + * + *==========================================================================*/ +nsecs_t QCamera3HardwareInterface::getBootToMonoTimeOffset() +{ + // try three times to get the clock offset, choose the one + // with the minimum gap in measurements. + const int tries = 3; + nsecs_t bestGap, measured; + for (int i = 0; i < tries; ++i) { + const nsecs_t tmono = systemTime(SYSTEM_TIME_MONOTONIC); + const nsecs_t tbase = systemTime(SYSTEM_TIME_BOOTTIME); + const nsecs_t tmono2 = systemTime(SYSTEM_TIME_MONOTONIC); + const nsecs_t gap = tmono2 - tmono; + if (i == 0 || gap < bestGap) { + bestGap = gap; + measured = tbase - ((tmono + tmono2) >> 1); + } + } + return measured; +} + }; //end namespace qcamera diff --git a/camera/QCamera2/HAL3/QCamera3HWI.h b/camera/QCamera2/HAL3/QCamera3HWI.h index b444e72..6cf6b5d 100644 --- a/camera/QCamera2/HAL3/QCamera3HWI.h +++ b/camera/QCamera2/HAL3/QCamera3HWI.h @@ -64,7 +64,6 @@ using ::android::hardware::camera::common::V1_0::helper::CameraMetadata; #endif /* Time related macros */ -typedef int64_t nsecs_t; #define NSEC_PER_SEC 1000000000LLU #define NSEC_PER_USEC 1000LLU #define NSEC_PER_33MSEC 33000000LLU @@ -292,6 +291,7 @@ private: int32_t notifyErrorForPendingRequests(); int32_t getReprocessibleOutputStreamId(uint32_t &id); int32_t handleCameraDeviceError(); + nsecs_t getBootToMonoTimeOffset(); bool isOnEncoder(const cam_dimension_t max_viewfinder_size, uint32_t width, uint32_t height); @@ -497,6 +497,9 @@ private: uint32_t mSurfaceStridePadding; State mState; + //The offset between BOOTTIME and MONOTONIC timestamps + nsecs_t mBootToMonoTimestampOffset; + bool mUseAVTimer; }; }; // namespace qcamera diff --git a/vendor_prop.mk b/vendor_prop.mk index bcb0091..c7418c2 100644 --- a/vendor_prop.mk +++ b/vendor_prop.mk @@ -16,7 +16,7 @@ # Camera PRODUCT_PROPERTY_OVERRIDES += \ - media.camera.ts.monotonic=0 + media.camera.ts.monotonic=1 # Properties PRODUCT_PROPERTY_OVERRIDES += \