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 179a59de880cc82d8175e40a3bfcebffbadbb33efdPin Tingpackage com.android.camera; 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 String TAG = "MosaicFrameProcessor"; 268a2c41754655a3733175fce81fb7506ff7022959Angus Kong private static final int NUM_FRAMES_IN_BUFFER = 2; 278a2c41754655a3733175fce81fb7506ff7022959Angus Kong private static final int MAX_NUMBER_OF_FRAMES = 100; 28dd28e1cc00373c02adf88dff878dbbe5d8be9e59mbansal private static final int MOSAIC_RET_CODE_INDEX = 10; 298a2c41754655a3733175fce81fb7506ff7022959Angus Kong private static final int FRAME_COUNT_INDEX = 9; 308a2c41754655a3733175fce81fb7506ff7022959Angus Kong private static final int X_COORD_INDEX = 2; 318a2c41754655a3733175fce81fb7506ff7022959Angus Kong private static final int Y_COORD_INDEX = 5; 3243b0b2ccd5949ee8fc377c37e7e2b82a26c88ca8Wei-Ta Chen private static final int HR_TO_LR_DOWNSAMPLE_FACTOR = 4; 33e47b5624a1aa3cc7bd9763852bed4ac3215a77b2Wei-Ta Chen private static final int WINDOW_SIZE = 3; 348a2c41754655a3733175fce81fb7506ff7022959Angus Kong 358a2c41754655a3733175fce81fb7506ff7022959Angus Kong private Mosaic mMosaicer; 360adf2489520d3a98a56e081aeacb1ab9336a012fWei-Ta Chen private boolean mIsMosaicMemoryAllocated = false; 378a2c41754655a3733175fce81fb7506ff7022959Angus Kong private float mTranslationLastX; 388a2c41754655a3733175fce81fb7506ff7022959Angus Kong private float mTranslationLastY; 398a2c41754655a3733175fce81fb7506ff7022959Angus Kong 408a2c41754655a3733175fce81fb7506ff7022959Angus Kong private int mFillIn = 0; 418a2c41754655a3733175fce81fb7506ff7022959Angus Kong private int mTotalFrameCount = 0; 428a2c41754655a3733175fce81fb7506ff7022959Angus Kong private int mLastProcessFrameIdx = -1; 438a2c41754655a3733175fce81fb7506ff7022959Angus Kong private int mCurrProcessFrameIdx = -1; 44b7e4d024214b85e8570ad0d8ce03472887364beeWu-cheng Li private boolean mFirstRun; 458a2c41754655a3733175fce81fb7506ff7022959Angus Kong 46b7e4d024214b85e8570ad0d8ce03472887364beeWu-cheng Li // Panning rate is in unit of percentage of image content translation per 47b7e4d024214b85e8570ad0d8ce03472887364beeWu-cheng Li // frame. Use moving average to calculate the panning rate. 4843b0b2ccd5949ee8fc377c37e7e2b82a26c88ca8Wei-Ta Chen private float mPanningRateX; 4943b0b2ccd5949ee8fc377c37e7e2b82a26c88ca8Wei-Ta Chen private float mPanningRateY; 508a2c41754655a3733175fce81fb7506ff7022959Angus Kong 51e47b5624a1aa3cc7bd9763852bed4ac3215a77b2Wei-Ta Chen private float[] mDeltaX = new float[WINDOW_SIZE]; 52e47b5624a1aa3cc7bd9763852bed4ac3215a77b2Wei-Ta Chen private float[] mDeltaY = new float[WINDOW_SIZE]; 53e47b5624a1aa3cc7bd9763852bed4ac3215a77b2Wei-Ta Chen private int mOldestIdx = 0; 54e47b5624a1aa3cc7bd9763852bed4ac3215a77b2Wei-Ta Chen private float mTotalTranslationX = 0f; 55e47b5624a1aa3cc7bd9763852bed4ac3215a77b2Wei-Ta Chen private float mTotalTranslationY = 0f; 56e47b5624a1aa3cc7bd9763852bed4ac3215a77b2Wei-Ta Chen 57e47b5624a1aa3cc7bd9763852bed4ac3215a77b2Wei-Ta Chen private ProgressListener mProgressListener; 58e47b5624a1aa3cc7bd9763852bed4ac3215a77b2Wei-Ta Chen 5994f592fc405ca45b8794007cd9083c3250924b50Wei-Ta Chen private int mPreviewWidth; 6094f592fc405ca45b8794007cd9083c3250924b50Wei-Ta Chen private int mPreviewHeight; 6194f592fc405ca45b8794007cd9083c3250924b50Wei-Ta Chen private int mPreviewBufferSize; 6294f592fc405ca45b8794007cd9083c3250924b50Wei-Ta Chen 6303f6dd690441ee744bee2128cc194c2cdeb962e6Wu-cheng Li private static MosaicFrameProcessor sMosaicFrameProcessor; // singleton 6403f6dd690441ee744bee2128cc194c2cdeb962e6Wu-cheng Li 658a2c41754655a3733175fce81fb7506ff7022959Angus Kong public interface ProgressListener { 66d991766dc3bcc03a02c6648e2cfd54ee4f8cbd9eAngus Kong public void onProgress(boolean isFinished, float panningRateX, float panningRateY, 67d991766dc3bcc03a02c6648e2cfd54ee4f8cbd9eAngus Kong float progressX, float progressY); 688a2c41754655a3733175fce81fb7506ff7022959Angus Kong } 698a2c41754655a3733175fce81fb7506ff7022959Angus Kong 7003f6dd690441ee744bee2128cc194c2cdeb962e6Wu-cheng Li public static MosaicFrameProcessor getInstance() { 7103f6dd690441ee744bee2128cc194c2cdeb962e6Wu-cheng Li if (sMosaicFrameProcessor == null) { 7203f6dd690441ee744bee2128cc194c2cdeb962e6Wu-cheng Li sMosaicFrameProcessor = new MosaicFrameProcessor(); 7303f6dd690441ee744bee2128cc194c2cdeb962e6Wu-cheng Li } 7403f6dd690441ee744bee2128cc194c2cdeb962e6Wu-cheng Li return sMosaicFrameProcessor; 7503f6dd690441ee744bee2128cc194c2cdeb962e6Wu-cheng Li } 7603f6dd690441ee744bee2128cc194c2cdeb962e6Wu-cheng Li 7703f6dd690441ee744bee2128cc194c2cdeb962e6Wu-cheng Li private MosaicFrameProcessor() { 788a2c41754655a3733175fce81fb7506ff7022959Angus Kong mMosaicer = new Mosaic(); 798a2c41754655a3733175fce81fb7506ff7022959Angus Kong } 808a2c41754655a3733175fce81fb7506ff7022959Angus Kong 818a2c41754655a3733175fce81fb7506ff7022959Angus Kong public void setProgressListener(ProgressListener listener) { 828a2c41754655a3733175fce81fb7506ff7022959Angus Kong mProgressListener = listener; 838a2c41754655a3733175fce81fb7506ff7022959Angus Kong } 848a2c41754655a3733175fce81fb7506ff7022959Angus Kong 85e1178a73fd5756771d25d0b8375452450f509e99mbansal public int reportProgress(boolean hires, boolean cancel) { 86e1178a73fd5756771d25d0b8375452450f509e99mbansal return mMosaicer.reportProgress(hires, cancel); 8750b3c890986aadb3780b4da8c0b8dbb0f1422ebambansal } 8850b3c890986aadb3780b4da8c0b8dbb0f1422ebambansal 8903f6dd690441ee744bee2128cc194c2cdeb962e6Wu-cheng Li public void initialize(int previewWidth, int previewHeight, int bufSize) { 9003f6dd690441ee744bee2128cc194c2cdeb962e6Wu-cheng Li mPreviewWidth = previewWidth; 9103f6dd690441ee744bee2128cc194c2cdeb962e6Wu-cheng Li mPreviewHeight = previewHeight; 9203f6dd690441ee744bee2128cc194c2cdeb962e6Wu-cheng Li mPreviewBufferSize = bufSize; 930adf2489520d3a98a56e081aeacb1ab9336a012fWei-Ta Chen setupMosaicer(mPreviewWidth, mPreviewHeight, mPreviewBufferSize); 94b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal setStripType(Mosaic.STRIPTYPE_WIDE); 95142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong reset(); 9694f592fc405ca45b8794007cd9083c3250924b50Wei-Ta Chen } 9794f592fc405ca45b8794007cd9083c3250924b50Wei-Ta Chen 98142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong public void clear() { 997d9eadd0c6c38b3761b7e8d3fa3658d194810d60Jim Miller if (mIsMosaicMemoryAllocated) { 1007d9eadd0c6c38b3761b7e8d3fa3658d194810d60Jim Miller mMosaicer.freeMosaicMemory(); 10103f6dd690441ee744bee2128cc194c2cdeb962e6Wu-cheng Li mIsMosaicMemoryAllocated = false; 10203f6dd690441ee744bee2128cc194c2cdeb962e6Wu-cheng Li } 10303f6dd690441ee744bee2128cc194c2cdeb962e6Wu-cheng Li synchronized (this) { 10403f6dd690441ee744bee2128cc194c2cdeb962e6Wu-cheng Li notify(); 1057d9eadd0c6c38b3761b7e8d3fa3658d194810d60Jim Miller } 10694f592fc405ca45b8794007cd9083c3250924b50Wei-Ta Chen } 10794f592fc405ca45b8794007cd9083c3250924b50Wei-Ta Chen 10803f6dd690441ee744bee2128cc194c2cdeb962e6Wu-cheng Li public boolean isMosaicMemoryAllocated() { 10903f6dd690441ee744bee2128cc194c2cdeb962e6Wu-cheng Li return mIsMosaicMemoryAllocated; 11003f6dd690441ee744bee2128cc194c2cdeb962e6Wu-cheng Li } 11103f6dd690441ee744bee2128cc194c2cdeb962e6Wu-cheng Li 112b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal public void setStripType(int type) { 113b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal mMosaicer.setStripType(type); 114b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal } 115b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal 1160adf2489520d3a98a56e081aeacb1ab9336a012fWei-Ta Chen private void setupMosaicer(int previewWidth, int previewHeight, int bufSize) { 1178a2c41754655a3733175fce81fb7506ff7022959Angus Kong Log.v(TAG, "setupMosaicer w, h=" + previewWidth + ',' + previewHeight + ',' + bufSize); 11803f6dd690441ee744bee2128cc194c2cdeb962e6Wu-cheng Li 11903f6dd690441ee744bee2128cc194c2cdeb962e6Wu-cheng Li if (mIsMosaicMemoryAllocated) throw new RuntimeException("MosaicFrameProcessor in use!"); 1200adf2489520d3a98a56e081aeacb1ab9336a012fWei-Ta Chen mIsMosaicMemoryAllocated = true; 12103f6dd690441ee744bee2128cc194c2cdeb962e6Wu-cheng Li mMosaicer.allocateMosaicMemory(previewWidth, previewHeight); 12294f592fc405ca45b8794007cd9083c3250924b50Wei-Ta Chen } 12394f592fc405ca45b8794007cd9083c3250924b50Wei-Ta Chen 124142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong public void reset() { 125142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong // reset() can be called even if MosaicFrameProcessor is not initialized. 126142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong // Only counters will be changed. 127b7e4d024214b85e8570ad0d8ce03472887364beeWu-cheng Li mFirstRun = true; 128142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong mTotalFrameCount = 0; 129142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong mFillIn = 0; 130e47b5624a1aa3cc7bd9763852bed4ac3215a77b2Wei-Ta Chen mTotalTranslationX = 0; 131e47b5624a1aa3cc7bd9763852bed4ac3215a77b2Wei-Ta Chen mTranslationLastX = 0; 132e47b5624a1aa3cc7bd9763852bed4ac3215a77b2Wei-Ta Chen mTotalTranslationY = 0; 133e47b5624a1aa3cc7bd9763852bed4ac3215a77b2Wei-Ta Chen mTranslationLastY = 0; 134e47b5624a1aa3cc7bd9763852bed4ac3215a77b2Wei-Ta Chen mPanningRateX = 0; 135e47b5624a1aa3cc7bd9763852bed4ac3215a77b2Wei-Ta Chen mPanningRateY = 0; 136142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong mLastProcessFrameIdx = -1; 137142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong mCurrProcessFrameIdx = -1; 138e47b5624a1aa3cc7bd9763852bed4ac3215a77b2Wei-Ta Chen for (int i = 0; i < WINDOW_SIZE; ++i) { 139e47b5624a1aa3cc7bd9763852bed4ac3215a77b2Wei-Ta Chen mDeltaX[i] = 0f; 140e47b5624a1aa3cc7bd9763852bed4ac3215a77b2Wei-Ta Chen mDeltaY[i] = 0f; 141e47b5624a1aa3cc7bd9763852bed4ac3215a77b2Wei-Ta Chen } 142142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong mMosaicer.reset(); 14394f592fc405ca45b8794007cd9083c3250924b50Wei-Ta Chen } 14494f592fc405ca45b8794007cd9083c3250924b50Wei-Ta Chen 145e1178a73fd5756771d25d0b8375452450f509e99mbansal public int createMosaic(boolean highRes) { 146e1178a73fd5756771d25d0b8375452450f509e99mbansal return mMosaicer.createMosaic(highRes); 1478a2c41754655a3733175fce81fb7506ff7022959Angus Kong } 1488a2c41754655a3733175fce81fb7506ff7022959Angus Kong 1498a2c41754655a3733175fce81fb7506ff7022959Angus Kong public byte[] getFinalMosaicNV21() { 1508a2c41754655a3733175fce81fb7506ff7022959Angus Kong return mMosaicer.getFinalMosaicNV21(); 1518a2c41754655a3733175fce81fb7506ff7022959Angus Kong } 1528a2c41754655a3733175fce81fb7506ff7022959Angus Kong 1538a2c41754655a3733175fce81fb7506ff7022959Angus Kong // Processes the last filled image frame through the mosaicer and 1548a2c41754655a3733175fce81fb7506ff7022959Angus Kong // updates the UI to show progress. 1558a2c41754655a3733175fce81fb7506ff7022959Angus Kong // When done, processes and displays the final mosaic. 1560adf2489520d3a98a56e081aeacb1ab9336a012fWei-Ta Chen public void processFrame() { 1570adf2489520d3a98a56e081aeacb1ab9336a012fWei-Ta Chen if (!mIsMosaicMemoryAllocated) { 158142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong // clear() is called and buffers are cleared, stop computation. 159142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong // This can happen when the onPause() is called in the activity, but still some frames 160142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong // are not processed yet and thus the callback may be invoked. 161142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong return; 162142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong } 16341a2e9735136f372de95652d0828600282c8e967mbansal 1648a2c41754655a3733175fce81fb7506ff7022959Angus Kong mCurrProcessFrameIdx = mFillIn; 1658a2c41754655a3733175fce81fb7506ff7022959Angus Kong mFillIn = ((mFillIn + 1) % NUM_FRAMES_IN_BUFFER); 1668a2c41754655a3733175fce81fb7506ff7022959Angus Kong 1678a2c41754655a3733175fce81fb7506ff7022959Angus Kong // Check that we are trying to process a frame different from the 1688a2c41754655a3733175fce81fb7506ff7022959Angus Kong // last one processed (useful if this class was running asynchronously) 1698a2c41754655a3733175fce81fb7506ff7022959Angus Kong if (mCurrProcessFrameIdx != mLastProcessFrameIdx) { 1708a2c41754655a3733175fce81fb7506ff7022959Angus Kong mLastProcessFrameIdx = mCurrProcessFrameIdx; 1718a2c41754655a3733175fce81fb7506ff7022959Angus Kong 1721f227d20aa000d0798581f451b89b1d3b2bcd349Wei-Ta Chen // TODO: make the termination condition regarding reaching 1731f227d20aa000d0798581f451b89b1d3b2bcd349Wei-Ta Chen // MAX_NUMBER_OF_FRAMES solely determined in the library. 174c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong if (mTotalFrameCount < MAX_NUMBER_OF_FRAMES) { 1758a2c41754655a3733175fce81fb7506ff7022959Angus Kong // If we are still collecting new frames for the current mosaic, 1768a2c41754655a3733175fce81fb7506ff7022959Angus Kong // process the new frame. 177b7e4d024214b85e8570ad0d8ce03472887364beeWu-cheng Li calculateTranslationRate(); 1788a2c41754655a3733175fce81fb7506ff7022959Angus Kong 1798a2c41754655a3733175fce81fb7506ff7022959Angus Kong // Publish progress of the ongoing processing 1808a2c41754655a3733175fce81fb7506ff7022959Angus Kong if (mProgressListener != null) { 181d991766dc3bcc03a02c6648e2cfd54ee4f8cbd9eAngus Kong mProgressListener.onProgress(false, mPanningRateX, mPanningRateY, 182d991766dc3bcc03a02c6648e2cfd54ee4f8cbd9eAngus Kong mTranslationLastX * HR_TO_LR_DOWNSAMPLE_FACTOR / mPreviewWidth, 183d991766dc3bcc03a02c6648e2cfd54ee4f8cbd9eAngus Kong mTranslationLastY * HR_TO_LR_DOWNSAMPLE_FACTOR / mPreviewHeight); 1848a2c41754655a3733175fce81fb7506ff7022959Angus Kong } 1858a2c41754655a3733175fce81fb7506ff7022959Angus Kong } else { 1868a2c41754655a3733175fce81fb7506ff7022959Angus Kong if (mProgressListener != null) { 187d991766dc3bcc03a02c6648e2cfd54ee4f8cbd9eAngus Kong mProgressListener.onProgress(true, mPanningRateX, mPanningRateY, 188d991766dc3bcc03a02c6648e2cfd54ee4f8cbd9eAngus Kong mTranslationLastX * HR_TO_LR_DOWNSAMPLE_FACTOR / mPreviewWidth, 189d991766dc3bcc03a02c6648e2cfd54ee4f8cbd9eAngus Kong mTranslationLastY * HR_TO_LR_DOWNSAMPLE_FACTOR / mPreviewHeight); 1908a2c41754655a3733175fce81fb7506ff7022959Angus Kong } 1918a2c41754655a3733175fce81fb7506ff7022959Angus Kong } 1928a2c41754655a3733175fce81fb7506ff7022959Angus Kong } 1938a2c41754655a3733175fce81fb7506ff7022959Angus Kong } 1948a2c41754655a3733175fce81fb7506ff7022959Angus Kong 195b7e4d024214b85e8570ad0d8ce03472887364beeWu-cheng Li public void calculateTranslationRate() { 1960adf2489520d3a98a56e081aeacb1ab9336a012fWei-Ta Chen float[] frameData = mMosaicer.setSourceImageFromGPU(); 197dd28e1cc00373c02adf88dff878dbbe5d8be9e59mbansal int ret_code = (int) frameData[MOSAIC_RET_CODE_INDEX]; 1988a2c41754655a3733175fce81fb7506ff7022959Angus Kong mTotalFrameCount = (int) frameData[FRAME_COUNT_INDEX]; 1998a2c41754655a3733175fce81fb7506ff7022959Angus Kong float translationCurrX = frameData[X_COORD_INDEX]; 2008a2c41754655a3733175fce81fb7506ff7022959Angus Kong float translationCurrY = frameData[Y_COORD_INDEX]; 20143b0b2ccd5949ee8fc377c37e7e2b82a26c88ca8Wei-Ta Chen 202b7e4d024214b85e8570ad0d8ce03472887364beeWu-cheng Li if (mFirstRun) { 203e47b5624a1aa3cc7bd9763852bed4ac3215a77b2Wei-Ta Chen // First time: no need to update delta values. 204e47b5624a1aa3cc7bd9763852bed4ac3215a77b2Wei-Ta Chen mTranslationLastX = translationCurrX; 205e47b5624a1aa3cc7bd9763852bed4ac3215a77b2Wei-Ta Chen mTranslationLastY = translationCurrY; 206b7e4d024214b85e8570ad0d8ce03472887364beeWu-cheng Li mFirstRun = false; 207e47b5624a1aa3cc7bd9763852bed4ac3215a77b2Wei-Ta Chen return; 208e47b5624a1aa3cc7bd9763852bed4ac3215a77b2Wei-Ta Chen } 209e47b5624a1aa3cc7bd9763852bed4ac3215a77b2Wei-Ta Chen 210e47b5624a1aa3cc7bd9763852bed4ac3215a77b2Wei-Ta Chen // Moving average: remove the oldest translation/deltaTime and 211e47b5624a1aa3cc7bd9763852bed4ac3215a77b2Wei-Ta Chen // add the newest translation/deltaTime in 212e47b5624a1aa3cc7bd9763852bed4ac3215a77b2Wei-Ta Chen int idx = mOldestIdx; 213e47b5624a1aa3cc7bd9763852bed4ac3215a77b2Wei-Ta Chen mTotalTranslationX -= mDeltaX[idx]; 214e47b5624a1aa3cc7bd9763852bed4ac3215a77b2Wei-Ta Chen mTotalTranslationY -= mDeltaY[idx]; 215e47b5624a1aa3cc7bd9763852bed4ac3215a77b2Wei-Ta Chen mDeltaX[idx] = Math.abs(translationCurrX - mTranslationLastX); 216e47b5624a1aa3cc7bd9763852bed4ac3215a77b2Wei-Ta Chen mDeltaY[idx] = Math.abs(translationCurrY - mTranslationLastY); 217e47b5624a1aa3cc7bd9763852bed4ac3215a77b2Wei-Ta Chen mTotalTranslationX += mDeltaX[idx]; 218e47b5624a1aa3cc7bd9763852bed4ac3215a77b2Wei-Ta Chen mTotalTranslationY += mDeltaY[idx]; 219e47b5624a1aa3cc7bd9763852bed4ac3215a77b2Wei-Ta Chen 22043b0b2ccd5949ee8fc377c37e7e2b82a26c88ca8Wei-Ta Chen // The panning rate is measured as the rate of the translation percentage in 22143b0b2ccd5949ee8fc377c37e7e2b82a26c88ca8Wei-Ta Chen // image width/height. Take the horizontal panning rate for example, the image width 22243b0b2ccd5949ee8fc377c37e7e2b82a26c88ca8Wei-Ta Chen // used in finding the translation is (PreviewWidth / HR_TO_LR_DOWNSAMPLE_FACTOR). 22343b0b2ccd5949ee8fc377c37e7e2b82a26c88ca8Wei-Ta Chen // To get the horizontal translation percentage, the horizontal translation, 22443b0b2ccd5949ee8fc377c37e7e2b82a26c88ca8Wei-Ta Chen // (translationCurrX - mTranslationLastX), is divided by the 225b7e4d024214b85e8570ad0d8ce03472887364beeWu-cheng Li // image width. We then get the rate by dividing the translation percentage with the 226b7e4d024214b85e8570ad0d8ce03472887364beeWu-cheng Li // number of frames. 227d991766dc3bcc03a02c6648e2cfd54ee4f8cbd9eAngus Kong mPanningRateX = mTotalTranslationX / 228b7e4d024214b85e8570ad0d8ce03472887364beeWu-cheng Li (mPreviewWidth / HR_TO_LR_DOWNSAMPLE_FACTOR) / WINDOW_SIZE; 229d991766dc3bcc03a02c6648e2cfd54ee4f8cbd9eAngus Kong mPanningRateY = mTotalTranslationY / 230b7e4d024214b85e8570ad0d8ce03472887364beeWu-cheng Li (mPreviewHeight / HR_TO_LR_DOWNSAMPLE_FACTOR) / WINDOW_SIZE; 231d991766dc3bcc03a02c6648e2cfd54ee4f8cbd9eAngus Kong 232d991766dc3bcc03a02c6648e2cfd54ee4f8cbd9eAngus Kong mTranslationLastX = translationCurrX; 233d991766dc3bcc03a02c6648e2cfd54ee4f8cbd9eAngus Kong mTranslationLastY = translationCurrY; 234d991766dc3bcc03a02c6648e2cfd54ee4f8cbd9eAngus Kong mOldestIdx = (mOldestIdx + 1) % WINDOW_SIZE; 2358a2c41754655a3733175fce81fb7506ff7022959Angus Kong } 2368a2c41754655a3733175fce81fb7506ff7022959Angus Kong} 237