Home | History | Annotate | Download | only in util
      1 /* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
      2 *
      3 * Redistribution and use in source and binary forms, with or without
      4 * modification, are permitted provided that the following conditions are
      5 * met:
      6 *     * Redistributions of source code must retain the above copyright
      7 *       notice, this list of conditions and the following disclaimer.
      8 *     * Redistributions in binary form must reproduce the above
      9 *       copyright notice, this list of conditions and the following
     10 *       disclaimer in the documentation and/or other materials provided
     11 *       with the distribution.
     12 *     * Neither the name of The Linux Foundation nor the names of its
     13 *       contributors may be used to endorse or promote products derived
     14 *       from this software without specific prior written permission.
     15 *
     16 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
     17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
     18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
     19 * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
     20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
     23 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
     24 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
     25 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
     26 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     27 *
     28 */
     29 
     30 #define LOG_TAG "QCameraDisplay"
     31 
     32 // To remove
     33 #include <cutils/properties.h>
     34 
     35 // Camera dependencies
     36 #include "QCamera2HWI.h"
     37 #include "QCameraDisplay.h"
     38 
     39 extern "C" {
     40 #include "mm_camera_dbg.h"
     41 }
     42 
     43 #define CAMERA_VSYNC_WAIT_MS               33 // Used by vsync thread to wait for vsync timeout.
     44 #define DISPLAY_EVENT_RECEIVER_ARRAY_SIZE  1
     45 #define DISPLAY_DEFAULT_FPS                60
     46 
     47 namespace qcamera {
     48 
     49 /*===========================================================================
     50  * FUNCTION   : vsyncEventReceiverCamera
     51  *
     52  * DESCRIPTION: Computes average vsync interval. Called by display
     53  *              event handler for every vsync event.
     54  *
     55  * PARAMETERS :
     56  *   @fd      : file descriptor
     57  *   @events  : events
     58  *   @data    : pointer to user data provided during call back registration.
     59  *
     60  * RETURN     : always returns 1
     61  *==========================================================================*/
     62 int QCameraDisplay::vsyncEventReceiverCamera(__unused int fd,
     63                                              __unused int events, void* data) {
     64     android::DisplayEventReceiver::Event buffer[DISPLAY_EVENT_RECEIVER_ARRAY_SIZE];
     65     QCameraDisplay* pQCameraDisplay = (QCameraDisplay *) data;
     66     ssize_t n;
     67 
     68     while ((n = pQCameraDisplay->mDisplayEventReceiver.getEvents(buffer,
     69             DISPLAY_EVENT_RECEIVER_ARRAY_SIZE)) > 0) {
     70         for (int i = 0 ; i < n ; i++) {
     71             if (buffer[i].header.type == DisplayEventReceiver::DISPLAY_EVENT_VSYNC) {
     72                 pQCameraDisplay->computeAverageVsyncInterval(buffer[i].header.timestamp);
     73             }
     74         }
     75     }
     76     return 1;
     77 }
     78 
     79 /*===========================================================================
     80  * FUNCTION   : vsyncThreadCamera
     81  *
     82  * DESCRIPTION: Thread registers a call back function for every vsync event
     83  *              waits on the looper for the next vsync.
     84  *
     85  * PARAMETERS :
     86  *   @data    : receives vsync_info_t structure.
     87  *
     88  * RETURN     : NULL.Just to fullfill the type requirement of thread function.
     89  *==========================================================================*/
     90 void* QCameraDisplay::vsyncThreadCamera(void * data)
     91 {
     92     QCameraDisplay* pQCameraDisplay = (QCameraDisplay *) data;
     93     android::sp<Looper> looper;
     94 
     95     looper = new android::Looper(false);
     96     status_t status = pQCameraDisplay->mDisplayEventReceiver.initCheck();
     97     if (status != NO_ERROR) {
     98         LOGE("Initialization of DisplayEventReceiver failed with status: %d", status);
     99         return NULL;
    100     }
    101     looper->addFd(pQCameraDisplay->mDisplayEventReceiver.getFd(), 0, ALOOPER_EVENT_INPUT,
    102             QCameraDisplay::vsyncEventReceiverCamera, pQCameraDisplay);
    103     pQCameraDisplay->mDisplayEventReceiver.setVsyncRate(1);
    104     while(pQCameraDisplay->mThreadExit == 0)
    105     {
    106         looper->pollOnce(CAMERA_VSYNC_WAIT_MS);
    107     }
    108     return NULL;
    109 }
    110 
    111 /*===========================================================================
    112  * FUNCTION   : ~QCameraDisplay
    113  *
    114  * DESCRIPTION: constructor of QCameraDisplay
    115  *
    116  * PARAMETERS : none
    117  *
    118  * RETURN     : none
    119  *==========================================================================*/
    120 QCameraDisplay::QCameraDisplay()
    121     : mVsyncTimeStamp(0),
    122       mAvgVsyncInterval(0),
    123       mOldTimeStamp(0),
    124       mVsyncHistoryIndex(0),
    125       mAdditionalVsyncOffsetForWiggle(0),
    126       mThreadExit(0),
    127       mNum_vsync_from_vfe_isr_to_presentation_timestamp(0),
    128       mSet_timestamp_num_ms_prior_to_vsync(0),
    129       mVfe_and_mdp_freq_wiggle_filter_max_ms(0),
    130       mVfe_and_mdp_freq_wiggle_filter_min_ms(0)
    131 {
    132     int rc = NO_ERROR;
    133 
    134     memset(&mVsyncIntervalHistory, 0, sizeof(mVsyncIntervalHistory));
    135     rc = pthread_create(&mVsyncThreadCameraHandle, NULL, vsyncThreadCamera, (void *)this);
    136     if (rc == NO_ERROR) {
    137         char    value[PROPERTY_VALUE_MAX];
    138         nsecs_t default_vsync_interval;
    139         pthread_setname_np(mVsyncThreadCameraHandle, "CAM_Vsync_Thread");
    140         // Read a list of properties used for tuning
    141         property_get("persist.camera.disp.num_vsync", value, "4");
    142         mNum_vsync_from_vfe_isr_to_presentation_timestamp = atoi(value);
    143         property_get("persist.camera.disp.ms_to_vsync", value, "2");
    144         mSet_timestamp_num_ms_prior_to_vsync = atoi(value);
    145         property_get("persist.camera.disp.filter_max", value, "2");
    146         mVfe_and_mdp_freq_wiggle_filter_max_ms = atoi(value);
    147         property_get("persist.camera.disp.filter_min", value, "4");
    148         mVfe_and_mdp_freq_wiggle_filter_min_ms = atoi(value);
    149         property_get("persist.camera.disp.fps", value, "60");
    150         if (atoi(value) > 0) {
    151             default_vsync_interval= s2ns(1) / atoi(value);
    152         } else {
    153             default_vsync_interval= s2ns(1) / DISPLAY_DEFAULT_FPS;
    154         }
    155         for (int i=0; i < CAMERA_NUM_VSYNC_INTERVAL_HISTORY; i++) {
    156             mVsyncIntervalHistory[i] = default_vsync_interval;
    157         }
    158         LOGD("display jitter num_vsync_from_vfe_isr_to_presentation_timestamp %u \
    159                 set_timestamp_num_ms_prior_to_vsync %u",
    160                 mNum_vsync_from_vfe_isr_to_presentation_timestamp,
    161                 mSet_timestamp_num_ms_prior_to_vsync);
    162         LOGD("display jitter vfe_and_mdp_freq_wiggle_filter_max_ms %u \
    163                 vfe_and_mdp_freq_wiggle_filter_min_ms %u",
    164                 mVfe_and_mdp_freq_wiggle_filter_max_ms,
    165                 mVfe_and_mdp_freq_wiggle_filter_min_ms);
    166     } else {
    167         mVsyncThreadCameraHandle = 0;
    168     }
    169 }
    170 
    171 /*===========================================================================
    172  * FUNCTION   : ~QCameraDisplay
    173  *
    174  * DESCRIPTION: destructor of QCameraDisplay
    175  *
    176  * PARAMETERS : none
    177  *
    178  * RETURN     : none
    179  *==========================================================================*/
    180 QCameraDisplay::~QCameraDisplay()
    181 {
    182     mThreadExit = 1;
    183     if (mVsyncThreadCameraHandle != 0) {
    184         pthread_join(mVsyncThreadCameraHandle, NULL);
    185     }
    186 }
    187 
    188 /*===========================================================================
    189  * FUNCTION   : computeAverageVsyncInterval
    190  *
    191  * DESCRIPTION: Computes average vsync interval using current and previously
    192  *              stored vsync data.
    193  *
    194  * PARAMETERS : current vsync time stamp
    195  *
    196  * RETURN     : none
    197  *==========================================================================*/
    198 void QCameraDisplay::computeAverageVsyncInterval(nsecs_t currentVsyncTimeStamp)
    199 {
    200     nsecs_t sum;
    201     nsecs_t vsyncMaxOutlier;
    202     nsecs_t vsyncMinOutlier;
    203 
    204     mVsyncTimeStamp = currentVsyncTimeStamp;
    205     if (mOldTimeStamp) {
    206         // Compute average vsync interval using current and previously stored vsync data.
    207         // Leave the max and min vsync interval from history in computing the average.
    208         mVsyncIntervalHistory[mVsyncHistoryIndex] = currentVsyncTimeStamp - mOldTimeStamp;
    209         mVsyncHistoryIndex++;
    210         mVsyncHistoryIndex = mVsyncHistoryIndex % CAMERA_NUM_VSYNC_INTERVAL_HISTORY;
    211         sum = mVsyncIntervalHistory[0];
    212         vsyncMaxOutlier = mVsyncIntervalHistory[0];
    213         vsyncMinOutlier = mVsyncIntervalHistory[0];
    214         for (int j=1; j<CAMERA_NUM_VSYNC_INTERVAL_HISTORY; j++) {
    215             sum += mVsyncIntervalHistory[j];
    216             if (vsyncMaxOutlier < mVsyncIntervalHistory[j]) {
    217                 vsyncMaxOutlier = mVsyncIntervalHistory[j];
    218             } else if (vsyncMinOutlier > mVsyncIntervalHistory[j]) {
    219                 vsyncMinOutlier = mVsyncIntervalHistory[j];
    220             }
    221         }
    222         sum = sum - vsyncMaxOutlier - vsyncMinOutlier;
    223         mAvgVsyncInterval = sum / (CAMERA_NUM_VSYNC_INTERVAL_HISTORY - 2);
    224     }
    225     mOldTimeStamp = currentVsyncTimeStamp;
    226 }
    227 
    228 /*===========================================================================
    229  * FUNCTION   : computePresentationTimeStamp
    230  *
    231  * DESCRIPTION: Computes presentation time stamp using vsync interval
    232  *              and last vsync time stamp and few other tunable variables
    233  *              to place the time stamp at the expected future vsync
    234  *
    235  * PARAMETERS : current frame time stamp set by VFE when buffer copy done.
    236  *
    237  * RETURN     : time stamp in future or 0 in case of failure.
    238  *==========================================================================*/
    239 nsecs_t QCameraDisplay::computePresentationTimeStamp(nsecs_t frameTimeStamp)
    240 {
    241     nsecs_t moveToNextVsync;
    242     nsecs_t keepInCurrentVsync;
    243     nsecs_t timeDifference        = 0;
    244     nsecs_t presentationTimeStamp = 0;
    245     int     expectedVsyncOffset   = 0;
    246     int     vsyncOffset;
    247 
    248     if ( (mAvgVsyncInterval != 0) && (mVsyncTimeStamp != 0) ) {
    249         // Compute presentation time stamp in future as per the following formula
    250         // future time stamp = vfe time stamp +  N *  average vsync interval
    251         // Adjust the time stamp so that it is placed few milliseconds before
    252         // the expected vsync.
    253         // Adjust the time stamp for the period where vsync time stamp and VFE
    254         // timstamp cross over due difference in fps.
    255         presentationTimeStamp = frameTimeStamp +
    256                 (mNum_vsync_from_vfe_isr_to_presentation_timestamp * mAvgVsyncInterval);
    257         if (presentationTimeStamp > mVsyncTimeStamp) {
    258             timeDifference      = presentationTimeStamp - mVsyncTimeStamp;
    259             moveToNextVsync     = mAvgVsyncInterval - mVfe_and_mdp_freq_wiggle_filter_min_ms;
    260             keepInCurrentVsync  = mAvgVsyncInterval - mVfe_and_mdp_freq_wiggle_filter_max_ms;
    261             vsyncOffset         = timeDifference % mAvgVsyncInterval;
    262             expectedVsyncOffset = mAvgVsyncInterval -
    263                     mSet_timestamp_num_ms_prior_to_vsync - vsyncOffset;
    264             if (vsyncOffset > moveToNextVsync) {
    265                 mAdditionalVsyncOffsetForWiggle = mAvgVsyncInterval;
    266             } else if (vsyncOffset < keepInCurrentVsync) {
    267                 mAdditionalVsyncOffsetForWiggle = 0;
    268             }
    269             LOGD("vsyncTimeStamp: %llu presentationTimeStamp: %llu expectedVsyncOffset: %d \
    270                     timeDifference: %llu vsyncffset: %d avgvsync: %llu \
    271                     additionalvsyncOffsetForWiggle: %llu",
    272                     mVsyncTimeStamp, presentationTimeStamp, expectedVsyncOffset,
    273                     timeDifference, vsyncOffset, mAvgVsyncInterval,
    274                     mAdditionalVsyncOffsetForWiggle);
    275         }
    276         presentationTimeStamp = presentationTimeStamp + expectedVsyncOffset +
    277                 mAdditionalVsyncOffsetForWiggle;
    278     }
    279     return presentationTimeStamp;
    280 }
    281 
    282 }; // namespace qcamera
    283