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() { 947d9eadd0c6c38b3761b7e8d3fa3658d194810d60Jim Miller if (mIsMosaicMemoryAllocated) { 957d9eadd0c6c38b3761b7e8d3fa3658d194810d60Jim Miller mIsMosaicMemoryAllocated = false; 967d9eadd0c6c38b3761b7e8d3fa3658d194810d60Jim Miller mMosaicer.freeMosaicMemory(); 977d9eadd0c6c38b3761b7e8d3fa3658d194810d60Jim Miller } 9894f592fc405ca45b8794007cd9083c3250924b50Wei-Ta Chen } 9994f592fc405ca45b8794007cd9083c3250924b50Wei-Ta Chen 100b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal public void setStripType(int type) { 101b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal mMosaicer.setStripType(type); 102b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal } 103b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal 1040adf2489520d3a98a56e081aeacb1ab9336a012fWei-Ta Chen private void setupMosaicer(int previewWidth, int previewHeight, int bufSize) { 1058a2c41754655a3733175fce81fb7506ff7022959Angus Kong Log.v(TAG, "setupMosaicer w, h=" + previewWidth + ',' + previewHeight + ',' + bufSize); 10694f592fc405ca45b8794007cd9083c3250924b50Wei-Ta Chen mMosaicer.allocateMosaicMemory(previewWidth, previewHeight); 1070adf2489520d3a98a56e081aeacb1ab9336a012fWei-Ta Chen mIsMosaicMemoryAllocated = true; 10894f592fc405ca45b8794007cd9083c3250924b50Wei-Ta Chen 10994f592fc405ca45b8794007cd9083c3250924b50Wei-Ta Chen mFillIn = 0; 11094f592fc405ca45b8794007cd9083c3250924b50Wei-Ta Chen if (mMosaicer != null) { 11194f592fc405ca45b8794007cd9083c3250924b50Wei-Ta Chen mMosaicer.reset(); 11294f592fc405ca45b8794007cd9083c3250924b50Wei-Ta Chen } 11394f592fc405ca45b8794007cd9083c3250924b50Wei-Ta Chen } 11494f592fc405ca45b8794007cd9083c3250924b50Wei-Ta Chen 115142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong public void reset() { 116142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong // reset() can be called even if MosaicFrameProcessor is not initialized. 117142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong // Only counters will be changed. 118142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong mTotalFrameCount = 0; 119142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong mFillIn = 0; 120142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong mLastProcessedFrameTimestamp = 0; 121e47b5624a1aa3cc7bd9763852bed4ac3215a77b2Wei-Ta Chen mTotalTranslationX = 0; 122e47b5624a1aa3cc7bd9763852bed4ac3215a77b2Wei-Ta Chen mTranslationLastX = 0; 123e47b5624a1aa3cc7bd9763852bed4ac3215a77b2Wei-Ta Chen mTotalTranslationY = 0; 124e47b5624a1aa3cc7bd9763852bed4ac3215a77b2Wei-Ta Chen mTranslationLastY = 0; 125e47b5624a1aa3cc7bd9763852bed4ac3215a77b2Wei-Ta Chen mTotalDeltaTime = 0; 126e47b5624a1aa3cc7bd9763852bed4ac3215a77b2Wei-Ta Chen mPanningRateX = 0; 127e47b5624a1aa3cc7bd9763852bed4ac3215a77b2Wei-Ta Chen mPanningRateY = 0; 128142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong mLastProcessFrameIdx = -1; 129142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong mCurrProcessFrameIdx = -1; 130e47b5624a1aa3cc7bd9763852bed4ac3215a77b2Wei-Ta Chen for (int i = 0; i < WINDOW_SIZE; ++i) { 131e47b5624a1aa3cc7bd9763852bed4ac3215a77b2Wei-Ta Chen mDeltaX[i] = 0f; 132e47b5624a1aa3cc7bd9763852bed4ac3215a77b2Wei-Ta Chen mDeltaY[i] = 0f; 133e47b5624a1aa3cc7bd9763852bed4ac3215a77b2Wei-Ta Chen mDeltaTime[i] = 0f; 134e47b5624a1aa3cc7bd9763852bed4ac3215a77b2Wei-Ta Chen } 135142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong mMosaicer.reset(); 13694f592fc405ca45b8794007cd9083c3250924b50Wei-Ta Chen } 13794f592fc405ca45b8794007cd9083c3250924b50Wei-Ta Chen 138e1178a73fd5756771d25d0b8375452450f509e99mbansal public int createMosaic(boolean highRes) { 139e1178a73fd5756771d25d0b8375452450f509e99mbansal return mMosaicer.createMosaic(highRes); 1408a2c41754655a3733175fce81fb7506ff7022959Angus Kong } 1418a2c41754655a3733175fce81fb7506ff7022959Angus Kong 1428a2c41754655a3733175fce81fb7506ff7022959Angus Kong public byte[] getFinalMosaicNV21() { 1438a2c41754655a3733175fce81fb7506ff7022959Angus Kong return mMosaicer.getFinalMosaicNV21(); 1448a2c41754655a3733175fce81fb7506ff7022959Angus Kong } 1458a2c41754655a3733175fce81fb7506ff7022959Angus Kong 1468a2c41754655a3733175fce81fb7506ff7022959Angus Kong // Processes the last filled image frame through the mosaicer and 1478a2c41754655a3733175fce81fb7506ff7022959Angus Kong // updates the UI to show progress. 1488a2c41754655a3733175fce81fb7506ff7022959Angus Kong // When done, processes and displays the final mosaic. 1490adf2489520d3a98a56e081aeacb1ab9336a012fWei-Ta Chen public void processFrame() { 1500adf2489520d3a98a56e081aeacb1ab9336a012fWei-Ta Chen if (!mIsMosaicMemoryAllocated) { 151142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong // clear() is called and buffers are cleared, stop computation. 152142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong // This can happen when the onPause() is called in the activity, but still some frames 153142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong // are not processed yet and thus the callback may be invoked. 154142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong return; 155142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong } 1568a2c41754655a3733175fce81fb7506ff7022959Angus Kong long t1 = System.currentTimeMillis(); 1578a2c41754655a3733175fce81fb7506ff7022959Angus Kong mFrameTimestamp[mFillIn] = t1; 15841a2e9735136f372de95652d0828600282c8e967mbansal 1598a2c41754655a3733175fce81fb7506ff7022959Angus Kong mCurrProcessFrameIdx = mFillIn; 1608a2c41754655a3733175fce81fb7506ff7022959Angus Kong mFillIn = ((mFillIn + 1) % NUM_FRAMES_IN_BUFFER); 1618a2c41754655a3733175fce81fb7506ff7022959Angus Kong 1628a2c41754655a3733175fce81fb7506ff7022959Angus Kong // Check that we are trying to process a frame different from the 1638a2c41754655a3733175fce81fb7506ff7022959Angus Kong // last one processed (useful if this class was running asynchronously) 1648a2c41754655a3733175fce81fb7506ff7022959Angus Kong if (mCurrProcessFrameIdx != mLastProcessFrameIdx) { 1658a2c41754655a3733175fce81fb7506ff7022959Angus Kong mLastProcessFrameIdx = mCurrProcessFrameIdx; 1668a2c41754655a3733175fce81fb7506ff7022959Angus Kong 1670adf2489520d3a98a56e081aeacb1ab9336a012fWei-Ta Chen // Access the timestamp associated with it... 1688a2c41754655a3733175fce81fb7506ff7022959Angus Kong long timestamp = mFrameTimestamp[mCurrProcessFrameIdx]; 1698a2c41754655a3733175fce81fb7506ff7022959Angus Kong 1701f227d20aa000d0798581f451b89b1d3b2bcd349Wei-Ta Chen // TODO: make the termination condition regarding reaching 1711f227d20aa000d0798581f451b89b1d3b2bcd349Wei-Ta Chen // MAX_NUMBER_OF_FRAMES solely determined in the library. 172c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong if (mTotalFrameCount < MAX_NUMBER_OF_FRAMES) { 1738a2c41754655a3733175fce81fb7506ff7022959Angus Kong // If we are still collecting new frames for the current mosaic, 1748a2c41754655a3733175fce81fb7506ff7022959Angus Kong // process the new frame. 1750adf2489520d3a98a56e081aeacb1ab9336a012fWei-Ta Chen calculateTranslationRate(timestamp); 1768a2c41754655a3733175fce81fb7506ff7022959Angus Kong 1778a2c41754655a3733175fce81fb7506ff7022959Angus Kong // Publish progress of the ongoing processing 1788a2c41754655a3733175fce81fb7506ff7022959Angus Kong if (mProgressListener != null) { 179d991766dc3bcc03a02c6648e2cfd54ee4f8cbd9eAngus Kong mProgressListener.onProgress(false, mPanningRateX, mPanningRateY, 180d991766dc3bcc03a02c6648e2cfd54ee4f8cbd9eAngus Kong mTranslationLastX * HR_TO_LR_DOWNSAMPLE_FACTOR / mPreviewWidth, 181d991766dc3bcc03a02c6648e2cfd54ee4f8cbd9eAngus Kong mTranslationLastY * HR_TO_LR_DOWNSAMPLE_FACTOR / mPreviewHeight); 1828a2c41754655a3733175fce81fb7506ff7022959Angus Kong } 1838a2c41754655a3733175fce81fb7506ff7022959Angus Kong } else { 1848a2c41754655a3733175fce81fb7506ff7022959Angus Kong if (mProgressListener != null) { 185d991766dc3bcc03a02c6648e2cfd54ee4f8cbd9eAngus Kong mProgressListener.onProgress(true, mPanningRateX, mPanningRateY, 186d991766dc3bcc03a02c6648e2cfd54ee4f8cbd9eAngus Kong mTranslationLastX * HR_TO_LR_DOWNSAMPLE_FACTOR / mPreviewWidth, 187d991766dc3bcc03a02c6648e2cfd54ee4f8cbd9eAngus Kong mTranslationLastY * HR_TO_LR_DOWNSAMPLE_FACTOR / mPreviewHeight); 1888a2c41754655a3733175fce81fb7506ff7022959Angus Kong } 1898a2c41754655a3733175fce81fb7506ff7022959Angus Kong } 1908a2c41754655a3733175fce81fb7506ff7022959Angus Kong } 1918a2c41754655a3733175fce81fb7506ff7022959Angus Kong } 1928a2c41754655a3733175fce81fb7506ff7022959Angus Kong 1930adf2489520d3a98a56e081aeacb1ab9336a012fWei-Ta Chen public void calculateTranslationRate(long now) { 1940adf2489520d3a98a56e081aeacb1ab9336a012fWei-Ta Chen float[] frameData = mMosaicer.setSourceImageFromGPU(); 195dd28e1cc00373c02adf88dff878dbbe5d8be9e59mbansal int ret_code = (int) frameData[MOSAIC_RET_CODE_INDEX]; 1968a2c41754655a3733175fce81fb7506ff7022959Angus Kong mTotalFrameCount = (int) frameData[FRAME_COUNT_INDEX]; 1978a2c41754655a3733175fce81fb7506ff7022959Angus Kong float translationCurrX = frameData[X_COORD_INDEX]; 1988a2c41754655a3733175fce81fb7506ff7022959Angus Kong float translationCurrY = frameData[Y_COORD_INDEX]; 19943b0b2ccd5949ee8fc377c37e7e2b82a26c88ca8Wei-Ta Chen 200e47b5624a1aa3cc7bd9763852bed4ac3215a77b2Wei-Ta Chen if (mLastProcessedFrameTimestamp == 0f) { 201e47b5624a1aa3cc7bd9763852bed4ac3215a77b2Wei-Ta Chen // First time: no need to update delta values. 202e47b5624a1aa3cc7bd9763852bed4ac3215a77b2Wei-Ta Chen mTranslationLastX = translationCurrX; 203e47b5624a1aa3cc7bd9763852bed4ac3215a77b2Wei-Ta Chen mTranslationLastY = translationCurrY; 204e47b5624a1aa3cc7bd9763852bed4ac3215a77b2Wei-Ta Chen mLastProcessedFrameTimestamp = now; 205e47b5624a1aa3cc7bd9763852bed4ac3215a77b2Wei-Ta Chen return; 206e47b5624a1aa3cc7bd9763852bed4ac3215a77b2Wei-Ta Chen } 207e47b5624a1aa3cc7bd9763852bed4ac3215a77b2Wei-Ta Chen 208e47b5624a1aa3cc7bd9763852bed4ac3215a77b2Wei-Ta Chen // Moving average: remove the oldest translation/deltaTime and 209e47b5624a1aa3cc7bd9763852bed4ac3215a77b2Wei-Ta Chen // add the newest translation/deltaTime in 210e47b5624a1aa3cc7bd9763852bed4ac3215a77b2Wei-Ta Chen int idx = mOldestIdx; 211e47b5624a1aa3cc7bd9763852bed4ac3215a77b2Wei-Ta Chen mTotalTranslationX -= mDeltaX[idx]; 212e47b5624a1aa3cc7bd9763852bed4ac3215a77b2Wei-Ta Chen mTotalTranslationY -= mDeltaY[idx]; 213e47b5624a1aa3cc7bd9763852bed4ac3215a77b2Wei-Ta Chen mTotalDeltaTime -= mDeltaTime[idx]; 214e47b5624a1aa3cc7bd9763852bed4ac3215a77b2Wei-Ta Chen mDeltaX[idx] = Math.abs(translationCurrX - mTranslationLastX); 215e47b5624a1aa3cc7bd9763852bed4ac3215a77b2Wei-Ta Chen mDeltaY[idx] = Math.abs(translationCurrY - mTranslationLastY); 216e47b5624a1aa3cc7bd9763852bed4ac3215a77b2Wei-Ta Chen mDeltaTime[idx] = (now - mLastProcessedFrameTimestamp) / 1000.0f; 217e47b5624a1aa3cc7bd9763852bed4ac3215a77b2Wei-Ta Chen mTotalTranslationX += mDeltaX[idx]; 218e47b5624a1aa3cc7bd9763852bed4ac3215a77b2Wei-Ta Chen mTotalTranslationY += mDeltaY[idx]; 219e47b5624a1aa3cc7bd9763852bed4ac3215a77b2Wei-Ta Chen mTotalDeltaTime += mDeltaTime[idx]; 220e47b5624a1aa3cc7bd9763852bed4ac3215a77b2Wei-Ta Chen 22143b0b2ccd5949ee8fc377c37e7e2b82a26c88ca8Wei-Ta Chen // The panning rate is measured as the rate of the translation percentage in 22243b0b2ccd5949ee8fc377c37e7e2b82a26c88ca8Wei-Ta Chen // image width/height. Take the horizontal panning rate for example, the image width 22343b0b2ccd5949ee8fc377c37e7e2b82a26c88ca8Wei-Ta Chen // used in finding the translation is (PreviewWidth / HR_TO_LR_DOWNSAMPLE_FACTOR). 22443b0b2ccd5949ee8fc377c37e7e2b82a26c88ca8Wei-Ta Chen // To get the horizontal translation percentage, the horizontal translation, 22543b0b2ccd5949ee8fc377c37e7e2b82a26c88ca8Wei-Ta Chen // (translationCurrX - mTranslationLastX), is divided by the 22643b0b2ccd5949ee8fc377c37e7e2b82a26c88ca8Wei-Ta Chen // image width. We then get the rate by dividing the translation percentage with deltaTime. 227d991766dc3bcc03a02c6648e2cfd54ee4f8cbd9eAngus Kong mPanningRateX = mTotalTranslationX / 228d991766dc3bcc03a02c6648e2cfd54ee4f8cbd9eAngus Kong (mPreviewWidth / HR_TO_LR_DOWNSAMPLE_FACTOR) / mTotalDeltaTime; 229d991766dc3bcc03a02c6648e2cfd54ee4f8cbd9eAngus Kong mPanningRateY = mTotalTranslationY / 230d991766dc3bcc03a02c6648e2cfd54ee4f8cbd9eAngus Kong (mPreviewHeight / HR_TO_LR_DOWNSAMPLE_FACTOR) / mTotalDeltaTime; 231d991766dc3bcc03a02c6648e2cfd54ee4f8cbd9eAngus Kong 232d991766dc3bcc03a02c6648e2cfd54ee4f8cbd9eAngus Kong mTranslationLastX = translationCurrX; 233d991766dc3bcc03a02c6648e2cfd54ee4f8cbd9eAngus Kong mTranslationLastY = translationCurrY; 234d991766dc3bcc03a02c6648e2cfd54ee4f8cbd9eAngus Kong mLastProcessedFrameTimestamp = now; 235d991766dc3bcc03a02c6648e2cfd54ee4f8cbd9eAngus Kong mOldestIdx = (mOldestIdx + 1) % WINDOW_SIZE; 2368a2c41754655a3733175fce81fb7506ff7022959Angus Kong } 2378a2c41754655a3733175fce81fb7506ff7022959Angus Kong} 238