MosaicFrameProcessor.java revision d991766dc3bcc03a02c6648e2cfd54ee4f8cbd9e
18a2c41754655a3733175fce81fb7506ff7022959Angus Kong/* 28a2c41754655a3733175fce81fb7506ff7022959Angus Kong * Copyright (C) 2011 The Android Open Source Project 38a2c41754655a3733175fce81fb7506ff7022959Angus Kong * 48a2c41754655a3733175fce81fb7506ff7022959Angus Kong * Licensed under the Apache License, Version 2.0 (the "License"); 58a2c41754655a3733175fce81fb7506ff7022959Angus Kong * you may not use this file except in compliance with the License. 68a2c41754655a3733175fce81fb7506ff7022959Angus Kong * You may obtain a copy of the License at 78a2c41754655a3733175fce81fb7506ff7022959Angus Kong * 88a2c41754655a3733175fce81fb7506ff7022959Angus Kong * http://www.apache.org/licenses/LICENSE-2.0 98a2c41754655a3733175fce81fb7506ff7022959Angus Kong * 108a2c41754655a3733175fce81fb7506ff7022959Angus Kong * Unless required by applicable law or agreed to in writing, software 118a2c41754655a3733175fce81fb7506ff7022959Angus Kong * distributed under the License is distributed on an "AS IS" BASIS, 128a2c41754655a3733175fce81fb7506ff7022959Angus Kong * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 138a2c41754655a3733175fce81fb7506ff7022959Angus Kong * See the License for the specific language governing permissions and 148a2c41754655a3733175fce81fb7506ff7022959Angus Kong * limitations under the License. 158a2c41754655a3733175fce81fb7506ff7022959Angus Kong */ 168a2c41754655a3733175fce81fb7506ff7022959Angus Kong 178a2c41754655a3733175fce81fb7506ff7022959Angus Kongpackage com.android.camera.panorama; 188a2c41754655a3733175fce81fb7506ff7022959Angus Kong 198a2c41754655a3733175fce81fb7506ff7022959Angus Kongimport android.util.Log; 208a2c41754655a3733175fce81fb7506ff7022959Angus Kong 21142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong/** 22142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong * Class to handle the processing of each frame by Mosaicer. 23142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong */ 248a2c41754655a3733175fce81fb7506ff7022959Angus Kongpublic class MosaicFrameProcessor { 258a2c41754655a3733175fce81fb7506ff7022959Angus Kong private static final boolean LOGV = true; 268a2c41754655a3733175fce81fb7506ff7022959Angus Kong private static final String TAG = "MosaicFrameProcessor"; 278a2c41754655a3733175fce81fb7506ff7022959Angus Kong private static final int NUM_FRAMES_IN_BUFFER = 2; 288a2c41754655a3733175fce81fb7506ff7022959Angus Kong private static final int MAX_NUMBER_OF_FRAMES = 100; 29dd28e1cc00373c02adf88dff878dbbe5d8be9e59mbansal private static final int MOSAIC_RET_CODE_INDEX = 10; 308a2c41754655a3733175fce81fb7506ff7022959Angus Kong private static final int FRAME_COUNT_INDEX = 9; 318a2c41754655a3733175fce81fb7506ff7022959Angus Kong private static final int X_COORD_INDEX = 2; 328a2c41754655a3733175fce81fb7506ff7022959Angus Kong private static final int Y_COORD_INDEX = 5; 3343b0b2ccd5949ee8fc377c37e7e2b82a26c88ca8Wei-Ta Chen private static final int HR_TO_LR_DOWNSAMPLE_FACTOR = 4; 34e47b5624a1aa3cc7bd9763852bed4ac3215a77b2Wei-Ta Chen private static final int WINDOW_SIZE = 3; 358a2c41754655a3733175fce81fb7506ff7022959Angus Kong 368a2c41754655a3733175fce81fb7506ff7022959Angus Kong private Mosaic mMosaicer; 370adf2489520d3a98a56e081aeacb1ab9336a012fWei-Ta Chen private boolean mIsMosaicMemoryAllocated = false; 388a2c41754655a3733175fce81fb7506ff7022959Angus Kong private final long [] mFrameTimestamp = new long[NUM_FRAMES_IN_BUFFER]; 398a2c41754655a3733175fce81fb7506ff7022959Angus Kong private float mTranslationLastX; 408a2c41754655a3733175fce81fb7506ff7022959Angus Kong private float mTranslationLastY; 418a2c41754655a3733175fce81fb7506ff7022959Angus Kong 428a2c41754655a3733175fce81fb7506ff7022959Angus Kong private int mFillIn = 0; 438a2c41754655a3733175fce81fb7506ff7022959Angus Kong private int mTotalFrameCount = 0; 448a2c41754655a3733175fce81fb7506ff7022959Angus Kong private long mLastProcessedFrameTimestamp = 0; 458a2c41754655a3733175fce81fb7506ff7022959Angus Kong private int mLastProcessFrameIdx = -1; 468a2c41754655a3733175fce81fb7506ff7022959Angus Kong private int mCurrProcessFrameIdx = -1; 478a2c41754655a3733175fce81fb7506ff7022959Angus Kong 4843b0b2ccd5949ee8fc377c37e7e2b82a26c88ca8Wei-Ta Chen // Panning rate is in unit of percentage of image content translation / second. 49e47b5624a1aa3cc7bd9763852bed4ac3215a77b2Wei-Ta Chen // Use the moving average to calculate the panning rate. 5043b0b2ccd5949ee8fc377c37e7e2b82a26c88ca8Wei-Ta Chen private float mPanningRateX; 5143b0b2ccd5949ee8fc377c37e7e2b82a26c88ca8Wei-Ta Chen private float mPanningRateY; 528a2c41754655a3733175fce81fb7506ff7022959Angus Kong 53e47b5624a1aa3cc7bd9763852bed4ac3215a77b2Wei-Ta Chen private float[] mDeltaX = new float[WINDOW_SIZE]; 54e47b5624a1aa3cc7bd9763852bed4ac3215a77b2Wei-Ta Chen private float[] mDeltaY = new float[WINDOW_SIZE]; 55e47b5624a1aa3cc7bd9763852bed4ac3215a77b2Wei-Ta Chen private float[] mDeltaTime = new float[WINDOW_SIZE]; 56e47b5624a1aa3cc7bd9763852bed4ac3215a77b2Wei-Ta Chen private int mOldestIdx = 0; 57e47b5624a1aa3cc7bd9763852bed4ac3215a77b2Wei-Ta Chen private float mTotalTranslationX = 0f; 58e47b5624a1aa3cc7bd9763852bed4ac3215a77b2Wei-Ta Chen private float mTotalTranslationY = 0f; 59e47b5624a1aa3cc7bd9763852bed4ac3215a77b2Wei-Ta Chen private float mTotalDeltaTime = 0f; 60e47b5624a1aa3cc7bd9763852bed4ac3215a77b2Wei-Ta Chen 61e47b5624a1aa3cc7bd9763852bed4ac3215a77b2Wei-Ta Chen private ProgressListener mProgressListener; 62e47b5624a1aa3cc7bd9763852bed4ac3215a77b2Wei-Ta Chen 6394f592fc405ca45b8794007cd9083c3250924b50Wei-Ta Chen private int mPreviewWidth; 6494f592fc405ca45b8794007cd9083c3250924b50Wei-Ta Chen private int mPreviewHeight; 6594f592fc405ca45b8794007cd9083c3250924b50Wei-Ta Chen private int mPreviewBufferSize; 6694f592fc405ca45b8794007cd9083c3250924b50Wei-Ta Chen 678a2c41754655a3733175fce81fb7506ff7022959Angus Kong public interface ProgressListener { 68d991766dc3bcc03a02c6648e2cfd54ee4f8cbd9eAngus Kong public void onProgress(boolean isFinished, float panningRateX, float panningRateY, 69d991766dc3bcc03a02c6648e2cfd54ee4f8cbd9eAngus Kong float progressX, float progressY); 708a2c41754655a3733175fce81fb7506ff7022959Angus Kong } 718a2c41754655a3733175fce81fb7506ff7022959Angus Kong 72c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong public MosaicFrameProcessor(int previewWidth, int previewHeight, int bufSize) { 738a2c41754655a3733175fce81fb7506ff7022959Angus Kong mMosaicer = new Mosaic(); 7494f592fc405ca45b8794007cd9083c3250924b50Wei-Ta Chen mPreviewWidth = previewWidth; 7594f592fc405ca45b8794007cd9083c3250924b50Wei-Ta Chen mPreviewHeight = previewHeight; 7694f592fc405ca45b8794007cd9083c3250924b50Wei-Ta Chen mPreviewBufferSize = bufSize; 778a2c41754655a3733175fce81fb7506ff7022959Angus Kong } 788a2c41754655a3733175fce81fb7506ff7022959Angus Kong 798a2c41754655a3733175fce81fb7506ff7022959Angus Kong public void setProgressListener(ProgressListener listener) { 808a2c41754655a3733175fce81fb7506ff7022959Angus Kong mProgressListener = listener; 818a2c41754655a3733175fce81fb7506ff7022959Angus Kong } 828a2c41754655a3733175fce81fb7506ff7022959Angus Kong 83e1178a73fd5756771d25d0b8375452450f509e99mbansal public int reportProgress(boolean hires, boolean cancel) { 84e1178a73fd5756771d25d0b8375452450f509e99mbansal return mMosaicer.reportProgress(hires, cancel); 8550b3c890986aadb3780b4da8c0b8dbb0f1422ebambansal } 8650b3c890986aadb3780b4da8c0b8dbb0f1422ebambansal 87142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong public void initialize() { 880adf2489520d3a98a56e081aeacb1ab9336a012fWei-Ta Chen setupMosaicer(mPreviewWidth, mPreviewHeight, mPreviewBufferSize); 89b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal setStripType(Mosaic.STRIPTYPE_WIDE); 90142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong reset(); 9194f592fc405ca45b8794007cd9083c3250924b50Wei-Ta Chen } 9294f592fc405ca45b8794007cd9083c3250924b50Wei-Ta Chen 93142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong public void clear() { 940adf2489520d3a98a56e081aeacb1ab9336a012fWei-Ta Chen mIsMosaicMemoryAllocated = false; 95142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong mMosaicer.freeMosaicMemory(); 9694f592fc405ca45b8794007cd9083c3250924b50Wei-Ta Chen } 9794f592fc405ca45b8794007cd9083c3250924b50Wei-Ta Chen 98b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal public void setStripType(int type) { 99b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal mMosaicer.setStripType(type); 100b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal } 101b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal 1020adf2489520d3a98a56e081aeacb1ab9336a012fWei-Ta Chen private void setupMosaicer(int previewWidth, int previewHeight, int bufSize) { 1038a2c41754655a3733175fce81fb7506ff7022959Angus Kong Log.v(TAG, "setupMosaicer w, h=" + previewWidth + ',' + previewHeight + ',' + bufSize); 10494f592fc405ca45b8794007cd9083c3250924b50Wei-Ta Chen mMosaicer.allocateMosaicMemory(previewWidth, previewHeight); 1050adf2489520d3a98a56e081aeacb1ab9336a012fWei-Ta Chen mIsMosaicMemoryAllocated = true; 10694f592fc405ca45b8794007cd9083c3250924b50Wei-Ta Chen 10794f592fc405ca45b8794007cd9083c3250924b50Wei-Ta Chen mFillIn = 0; 10894f592fc405ca45b8794007cd9083c3250924b50Wei-Ta Chen if (mMosaicer != null) { 10994f592fc405ca45b8794007cd9083c3250924b50Wei-Ta Chen mMosaicer.reset(); 11094f592fc405ca45b8794007cd9083c3250924b50Wei-Ta Chen } 11194f592fc405ca45b8794007cd9083c3250924b50Wei-Ta Chen } 11294f592fc405ca45b8794007cd9083c3250924b50Wei-Ta Chen 113142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong public void reset() { 114142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong // reset() can be called even if MosaicFrameProcessor is not initialized. 115142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong // Only counters will be changed. 116142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong mTotalFrameCount = 0; 117142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong mFillIn = 0; 118142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong mLastProcessedFrameTimestamp = 0; 119e47b5624a1aa3cc7bd9763852bed4ac3215a77b2Wei-Ta Chen mTotalTranslationX = 0; 120e47b5624a1aa3cc7bd9763852bed4ac3215a77b2Wei-Ta Chen mTranslationLastX = 0; 121e47b5624a1aa3cc7bd9763852bed4ac3215a77b2Wei-Ta Chen mTotalTranslationY = 0; 122e47b5624a1aa3cc7bd9763852bed4ac3215a77b2Wei-Ta Chen mTranslationLastY = 0; 123e47b5624a1aa3cc7bd9763852bed4ac3215a77b2Wei-Ta Chen mTotalDeltaTime = 0; 124e47b5624a1aa3cc7bd9763852bed4ac3215a77b2Wei-Ta Chen mPanningRateX = 0; 125e47b5624a1aa3cc7bd9763852bed4ac3215a77b2Wei-Ta Chen mPanningRateY = 0; 126142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong mLastProcessFrameIdx = -1; 127142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong mCurrProcessFrameIdx = -1; 128e47b5624a1aa3cc7bd9763852bed4ac3215a77b2Wei-Ta Chen for (int i = 0; i < WINDOW_SIZE; ++i) { 129e47b5624a1aa3cc7bd9763852bed4ac3215a77b2Wei-Ta Chen mDeltaX[i] = 0f; 130e47b5624a1aa3cc7bd9763852bed4ac3215a77b2Wei-Ta Chen mDeltaY[i] = 0f; 131e47b5624a1aa3cc7bd9763852bed4ac3215a77b2Wei-Ta Chen mDeltaTime[i] = 0f; 132e47b5624a1aa3cc7bd9763852bed4ac3215a77b2Wei-Ta Chen } 133142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong mMosaicer.reset(); 13494f592fc405ca45b8794007cd9083c3250924b50Wei-Ta Chen } 13594f592fc405ca45b8794007cd9083c3250924b50Wei-Ta Chen 136e1178a73fd5756771d25d0b8375452450f509e99mbansal public int createMosaic(boolean highRes) { 137e1178a73fd5756771d25d0b8375452450f509e99mbansal return mMosaicer.createMosaic(highRes); 1388a2c41754655a3733175fce81fb7506ff7022959Angus Kong } 1398a2c41754655a3733175fce81fb7506ff7022959Angus Kong 1408a2c41754655a3733175fce81fb7506ff7022959Angus Kong public byte[] getFinalMosaicNV21() { 1418a2c41754655a3733175fce81fb7506ff7022959Angus Kong return mMosaicer.getFinalMosaicNV21(); 1428a2c41754655a3733175fce81fb7506ff7022959Angus Kong } 1438a2c41754655a3733175fce81fb7506ff7022959Angus Kong 1448a2c41754655a3733175fce81fb7506ff7022959Angus Kong // Processes the last filled image frame through the mosaicer and 1458a2c41754655a3733175fce81fb7506ff7022959Angus Kong // updates the UI to show progress. 1468a2c41754655a3733175fce81fb7506ff7022959Angus Kong // When done, processes and displays the final mosaic. 1470adf2489520d3a98a56e081aeacb1ab9336a012fWei-Ta Chen public void processFrame() { 1480adf2489520d3a98a56e081aeacb1ab9336a012fWei-Ta Chen if (!mIsMosaicMemoryAllocated) { 149142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong // clear() is called and buffers are cleared, stop computation. 150142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong // This can happen when the onPause() is called in the activity, but still some frames 151142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong // are not processed yet and thus the callback may be invoked. 152142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong return; 153142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong } 1548a2c41754655a3733175fce81fb7506ff7022959Angus Kong long t1 = System.currentTimeMillis(); 1558a2c41754655a3733175fce81fb7506ff7022959Angus Kong mFrameTimestamp[mFillIn] = t1; 15641a2e9735136f372de95652d0828600282c8e967mbansal 1578a2c41754655a3733175fce81fb7506ff7022959Angus Kong mCurrProcessFrameIdx = mFillIn; 1588a2c41754655a3733175fce81fb7506ff7022959Angus Kong mFillIn = ((mFillIn + 1) % NUM_FRAMES_IN_BUFFER); 1598a2c41754655a3733175fce81fb7506ff7022959Angus Kong 1608a2c41754655a3733175fce81fb7506ff7022959Angus Kong // Check that we are trying to process a frame different from the 1618a2c41754655a3733175fce81fb7506ff7022959Angus Kong // last one processed (useful if this class was running asynchronously) 1628a2c41754655a3733175fce81fb7506ff7022959Angus Kong if (mCurrProcessFrameIdx != mLastProcessFrameIdx) { 1638a2c41754655a3733175fce81fb7506ff7022959Angus Kong mLastProcessFrameIdx = mCurrProcessFrameIdx; 1648a2c41754655a3733175fce81fb7506ff7022959Angus Kong 1650adf2489520d3a98a56e081aeacb1ab9336a012fWei-Ta Chen // Access the timestamp associated with it... 1668a2c41754655a3733175fce81fb7506ff7022959Angus Kong long timestamp = mFrameTimestamp[mCurrProcessFrameIdx]; 1678a2c41754655a3733175fce81fb7506ff7022959Angus Kong 1681f227d20aa000d0798581f451b89b1d3b2bcd349Wei-Ta Chen // TODO: make the termination condition regarding reaching 1691f227d20aa000d0798581f451b89b1d3b2bcd349Wei-Ta Chen // MAX_NUMBER_OF_FRAMES solely determined in the library. 170c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong if (mTotalFrameCount < MAX_NUMBER_OF_FRAMES) { 1718a2c41754655a3733175fce81fb7506ff7022959Angus Kong // If we are still collecting new frames for the current mosaic, 1728a2c41754655a3733175fce81fb7506ff7022959Angus Kong // process the new frame. 1730adf2489520d3a98a56e081aeacb1ab9336a012fWei-Ta Chen calculateTranslationRate(timestamp); 1748a2c41754655a3733175fce81fb7506ff7022959Angus Kong 1758a2c41754655a3733175fce81fb7506ff7022959Angus Kong // Publish progress of the ongoing processing 1768a2c41754655a3733175fce81fb7506ff7022959Angus Kong if (mProgressListener != null) { 177d991766dc3bcc03a02c6648e2cfd54ee4f8cbd9eAngus Kong mProgressListener.onProgress(false, mPanningRateX, mPanningRateY, 178d991766dc3bcc03a02c6648e2cfd54ee4f8cbd9eAngus Kong mTranslationLastX * HR_TO_LR_DOWNSAMPLE_FACTOR / mPreviewWidth, 179d991766dc3bcc03a02c6648e2cfd54ee4f8cbd9eAngus Kong mTranslationLastY * HR_TO_LR_DOWNSAMPLE_FACTOR / mPreviewHeight); 1808a2c41754655a3733175fce81fb7506ff7022959Angus Kong } 1818a2c41754655a3733175fce81fb7506ff7022959Angus Kong } else { 1828a2c41754655a3733175fce81fb7506ff7022959Angus Kong if (mProgressListener != null) { 183d991766dc3bcc03a02c6648e2cfd54ee4f8cbd9eAngus Kong mProgressListener.onProgress(true, mPanningRateX, mPanningRateY, 184d991766dc3bcc03a02c6648e2cfd54ee4f8cbd9eAngus Kong mTranslationLastX * HR_TO_LR_DOWNSAMPLE_FACTOR / mPreviewWidth, 185d991766dc3bcc03a02c6648e2cfd54ee4f8cbd9eAngus Kong mTranslationLastY * HR_TO_LR_DOWNSAMPLE_FACTOR / mPreviewHeight); 1868a2c41754655a3733175fce81fb7506ff7022959Angus Kong } 1878a2c41754655a3733175fce81fb7506ff7022959Angus Kong } 1888a2c41754655a3733175fce81fb7506ff7022959Angus Kong } 1898a2c41754655a3733175fce81fb7506ff7022959Angus Kong } 1908a2c41754655a3733175fce81fb7506ff7022959Angus Kong 1910adf2489520d3a98a56e081aeacb1ab9336a012fWei-Ta Chen public void calculateTranslationRate(long now) { 1920adf2489520d3a98a56e081aeacb1ab9336a012fWei-Ta Chen float[] frameData = mMosaicer.setSourceImageFromGPU(); 193dd28e1cc00373c02adf88dff878dbbe5d8be9e59mbansal int ret_code = (int) frameData[MOSAIC_RET_CODE_INDEX]; 1948a2c41754655a3733175fce81fb7506ff7022959Angus Kong mTotalFrameCount = (int) frameData[FRAME_COUNT_INDEX]; 1958a2c41754655a3733175fce81fb7506ff7022959Angus Kong float translationCurrX = frameData[X_COORD_INDEX]; 1968a2c41754655a3733175fce81fb7506ff7022959Angus Kong float translationCurrY = frameData[Y_COORD_INDEX]; 19743b0b2ccd5949ee8fc377c37e7e2b82a26c88ca8Wei-Ta Chen 198e47b5624a1aa3cc7bd9763852bed4ac3215a77b2Wei-Ta Chen if (mLastProcessedFrameTimestamp == 0f) { 199e47b5624a1aa3cc7bd9763852bed4ac3215a77b2Wei-Ta Chen // First time: no need to update delta values. 200e47b5624a1aa3cc7bd9763852bed4ac3215a77b2Wei-Ta Chen mTranslationLastX = translationCurrX; 201e47b5624a1aa3cc7bd9763852bed4ac3215a77b2Wei-Ta Chen mTranslationLastY = translationCurrY; 202e47b5624a1aa3cc7bd9763852bed4ac3215a77b2Wei-Ta Chen mLastProcessedFrameTimestamp = now; 203e47b5624a1aa3cc7bd9763852bed4ac3215a77b2Wei-Ta Chen return; 204e47b5624a1aa3cc7bd9763852bed4ac3215a77b2Wei-Ta Chen } 205e47b5624a1aa3cc7bd9763852bed4ac3215a77b2Wei-Ta Chen 206e47b5624a1aa3cc7bd9763852bed4ac3215a77b2Wei-Ta Chen // Moving average: remove the oldest translation/deltaTime and 207e47b5624a1aa3cc7bd9763852bed4ac3215a77b2Wei-Ta Chen // add the newest translation/deltaTime in 208e47b5624a1aa3cc7bd9763852bed4ac3215a77b2Wei-Ta Chen int idx = mOldestIdx; 209e47b5624a1aa3cc7bd9763852bed4ac3215a77b2Wei-Ta Chen mTotalTranslationX -= mDeltaX[idx]; 210e47b5624a1aa3cc7bd9763852bed4ac3215a77b2Wei-Ta Chen mTotalTranslationY -= mDeltaY[idx]; 211e47b5624a1aa3cc7bd9763852bed4ac3215a77b2Wei-Ta Chen mTotalDeltaTime -= mDeltaTime[idx]; 212e47b5624a1aa3cc7bd9763852bed4ac3215a77b2Wei-Ta Chen mDeltaX[idx] = Math.abs(translationCurrX - mTranslationLastX); 213e47b5624a1aa3cc7bd9763852bed4ac3215a77b2Wei-Ta Chen mDeltaY[idx] = Math.abs(translationCurrY - mTranslationLastY); 214e47b5624a1aa3cc7bd9763852bed4ac3215a77b2Wei-Ta Chen mDeltaTime[idx] = (now - mLastProcessedFrameTimestamp) / 1000.0f; 215e47b5624a1aa3cc7bd9763852bed4ac3215a77b2Wei-Ta Chen mTotalTranslationX += mDeltaX[idx]; 216e47b5624a1aa3cc7bd9763852bed4ac3215a77b2Wei-Ta Chen mTotalTranslationY += mDeltaY[idx]; 217e47b5624a1aa3cc7bd9763852bed4ac3215a77b2Wei-Ta Chen mTotalDeltaTime += mDeltaTime[idx]; 218e47b5624a1aa3cc7bd9763852bed4ac3215a77b2Wei-Ta Chen 21943b0b2ccd5949ee8fc377c37e7e2b82a26c88ca8Wei-Ta Chen // The panning rate is measured as the rate of the translation percentage in 22043b0b2ccd5949ee8fc377c37e7e2b82a26c88ca8Wei-Ta Chen // image width/height. Take the horizontal panning rate for example, the image width 22143b0b2ccd5949ee8fc377c37e7e2b82a26c88ca8Wei-Ta Chen // used in finding the translation is (PreviewWidth / HR_TO_LR_DOWNSAMPLE_FACTOR). 22243b0b2ccd5949ee8fc377c37e7e2b82a26c88ca8Wei-Ta Chen // To get the horizontal translation percentage, the horizontal translation, 22343b0b2ccd5949ee8fc377c37e7e2b82a26c88ca8Wei-Ta Chen // (translationCurrX - mTranslationLastX), is divided by the 22443b0b2ccd5949ee8fc377c37e7e2b82a26c88ca8Wei-Ta Chen // image width. We then get the rate by dividing the translation percentage with deltaTime. 225d991766dc3bcc03a02c6648e2cfd54ee4f8cbd9eAngus Kong mPanningRateX = mTotalTranslationX / 226d991766dc3bcc03a02c6648e2cfd54ee4f8cbd9eAngus Kong (mPreviewWidth / HR_TO_LR_DOWNSAMPLE_FACTOR) / mTotalDeltaTime; 227d991766dc3bcc03a02c6648e2cfd54ee4f8cbd9eAngus Kong mPanningRateY = mTotalTranslationY / 228d991766dc3bcc03a02c6648e2cfd54ee4f8cbd9eAngus Kong (mPreviewHeight / HR_TO_LR_DOWNSAMPLE_FACTOR) / mTotalDeltaTime; 229d991766dc3bcc03a02c6648e2cfd54ee4f8cbd9eAngus Kong 230d991766dc3bcc03a02c6648e2cfd54ee4f8cbd9eAngus Kong mTranslationLastX = translationCurrX; 231d991766dc3bcc03a02c6648e2cfd54ee4f8cbd9eAngus Kong mTranslationLastY = translationCurrY; 232d991766dc3bcc03a02c6648e2cfd54ee4f8cbd9eAngus Kong mLastProcessedFrameTimestamp = now; 233d991766dc3bcc03a02c6648e2cfd54ee4f8cbd9eAngus Kong mOldestIdx = (mOldestIdx + 1) % WINDOW_SIZE; 2348a2c41754655a3733175fce81fb7506ff7022959Angus Kong } 2358a2c41754655a3733175fce81fb7506ff7022959Angus Kong} 236