/* * Copyright (C) 2011 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.wistron.WiCamera.WiPanorama; import Utilities.CSStaticData; import android.util.Log; /** * Class to handle the processing of each frame by Mosaicer. */ public class MosaicFrameProcessor { private static final boolean LOGV = true; private static final String TAG = "MosaicFrameProcessor"; private static final int NUM_FRAMES_IN_BUFFER = 2; public static final int MAX_NUMBER_OF_FRAMES = 100; private static final int MOSAIC_RET_CODE_INDEX = 10; private static final int FRAME_COUNT_INDEX = 9; private static final int X_COORD_INDEX = 2; private static final int Y_COORD_INDEX = 5; private static final int HR_TO_LR_DOWNSAMPLE_FACTOR = 4; private static final int WINDOW_SIZE = 3; private Mosaic mMosaicer; private boolean mIsMosaicMemoryAllocated = false; private final long [] mFrameTimestamp = new long[NUM_FRAMES_IN_BUFFER]; private float mTranslationLastX; private float mTranslationLastY; public int curframe=0; private int mFillIn = 0; private int mTotalFrameCount = 0; private long mLastProcessedFrameTimestamp = 0; private int mLastProcessFrameIdx = -1; private int mCurrProcessFrameIdx = -1; // Panning rate is in unit of percentage of image content translation / second. // Use the moving average to calculate the panning rate. private float mPanningRateX; private float mPanningRateY; private float[] mDeltaX = new float[WINDOW_SIZE]; private float[] mDeltaY = new float[WINDOW_SIZE]; private float[] mDeltaTime = new float[WINDOW_SIZE]; private int mOldestIdx = 0; private float mTotalTranslationX = 0f; private float mTotalTranslationY = 0f; private float mTotalDeltaTime = 0f; private ProgressListener mProgressListener; private int mPreviewWidth; private int mPreviewHeight; private int mPreviewBufferSize; public interface ProgressListener { public void onProgress(boolean isFinished, float panningRateX, float panningRateY, float progressX, float progressY); } public MosaicFrameProcessor(int previewWidth, int previewHeight, int bufSize) { mMosaicer = new Mosaic(); mPreviewWidth = previewWidth; mPreviewHeight = previewHeight; mPreviewBufferSize = bufSize; } public void setProgressListener(ProgressListener listener) { mProgressListener = listener; } public int reportProgress(boolean hires, boolean cancel) { return mMosaicer.reportProgress(hires, cancel); } public void initialize() { setupMosaicer(mPreviewWidth, mPreviewHeight, mPreviewBufferSize); setStripType(Mosaic.STRIPTYPE_WIDE); reset(); } public void initialize(boolean is3D) { setupMosaicer(mPreviewWidth, mPreviewHeight, mPreviewBufferSize,is3D); setStripType(Mosaic.STRIPTYPE_WIDE); reset(); } public void clear(boolean is3D) { if (mIsMosaicMemoryAllocated) { mIsMosaicMemoryAllocated = false; if(CSStaticData.DEBUG) Log.e(TAG, "----------------------[清除了mosaic内存——C]clearMosaicFrameProcessorIfNeeded------------------"); mMosaicer.freeMosaicMemory3D(is3D); } } public void setStripType(int type) { mMosaicer.setStripType(type); } private void setupMosaicer(int previewWidth, int previewHeight, int bufSize) { Log.v(TAG, "setupMosaicer w, h=" + previewWidth + ',' + previewHeight + ',' + bufSize); //Log.e("alloc 1", "ok"); mMosaicer.allocateMosaicMemory(previewWidth, previewHeight); // Log.e("alloc 2", "ok"); mIsMosaicMemoryAllocated = true; mFillIn = 0; if (mMosaicer != null) { mMosaicer.reset(); } } private void setupMosaicer(int previewWidth, int previewHeight, int bufSize,boolean is3D) { Log.v(TAG, "setupMosaicer w, h=" + previewWidth + ',' + previewHeight + ',' + bufSize); //Log.e("alloc 1", "ok"); mMosaicer.allocateMosaicMemory3D(previewWidth, previewHeight,is3D); // Log.e("alloc 2", "ok"); mIsMosaicMemoryAllocated = true; mFillIn = 0; if (mMosaicer != null) { mMosaicer.reset(); } } public void reset() { // reset() can be called even if MosaicFrameProcessor is not initialized. // Only counters will be changed. mTotalFrameCount = 0; mFillIn = 0; mLastProcessedFrameTimestamp = 0; mTotalTranslationX = 0; mTranslationLastX = 0; mTotalTranslationY = 0; mTranslationLastY = 0; mTotalDeltaTime = 0; mPanningRateX = 0; mPanningRateY = 0; mLastProcessFrameIdx = -1; mCurrProcessFrameIdx = -1; for (int i = 0; i < WINDOW_SIZE; ++i) { mDeltaX[i] = 0f; mDeltaY[i] = 0f; mDeltaTime[i] = 0f; } mMosaicer.reset(); } public int createMosaic(boolean highRes) { return mMosaicer.createMosaic(highRes); } public int createMosaic(boolean highRes,boolean isleft) { return mMosaicer.createMosaic3D(highRes,isleft); } public int createMosaic2D(boolean highRes) { return mMosaicer.createMosaic(highRes); } public int[] getFinalMosaicInt() { return mMosaicer.getFinalMosaic(); } public byte[] getFinalMosaicNV21() { return mMosaicer.getFinalMosaicNV21(); } // Processes the last filled image frame through the mosaicer and // updates the UI to show progress. // When done, processes and displays the final mosaic. public void processFrame( ) { if (!mIsMosaicMemoryAllocated) { // clear() is called and buffers are cleared, stop computation. // This can happen when the onPause() is called in the activity, but still some frames // are not processed yet and thus the callback may be invoked. return; } long t1 = System.currentTimeMillis(); mFrameTimestamp[mFillIn] = t1; mCurrProcessFrameIdx = mFillIn; mFillIn = ((mFillIn + 1) % NUM_FRAMES_IN_BUFFER); // Check that we are trying to process a frame different from the // last one processed (useful if this class was running asynchronously) if (mCurrProcessFrameIdx != mLastProcessFrameIdx) { mLastProcessFrameIdx = mCurrProcessFrameIdx; // Access the timestamp associated with it... long timestamp = mFrameTimestamp[mCurrProcessFrameIdx]; // TODO: make the termination condition regarding reaching // MAX_NUMBER_OF_FRAMES solely determined in the library. if (mTotalFrameCount < MAX_NUMBER_OF_FRAMES) { // If we are still collecting new frames for the current mosaic, // process the new frame. calculateTranslationRate(timestamp); // Publish progress of the ongoing processing if (mProgressListener != null) { mProgressListener.onProgress(false, mPanningRateX, mPanningRateY, mTranslationLastX * HR_TO_LR_DOWNSAMPLE_FACTOR / mPreviewWidth, mTranslationLastY * HR_TO_LR_DOWNSAMPLE_FACTOR / mPreviewHeight); } } else { if (mProgressListener != null) { mProgressListener.onProgress(true, mPanningRateX, mPanningRateY, mTranslationLastX * HR_TO_LR_DOWNSAMPLE_FACTOR / mPreviewWidth, mTranslationLastY * HR_TO_LR_DOWNSAMPLE_FACTOR / mPreviewHeight); } } } } public void processFrame(byte[] prebyte ) { if (!mIsMosaicMemoryAllocated) { // clear() is called and buffers are cleared, stop computation. // This can happen when the onPause() is called in the activity, but still some frames // are not processed yet and thus the callback may be invoked. return; } long t1 = System.currentTimeMillis(); mFrameTimestamp[mFillIn] = t1; mCurrProcessFrameIdx = mFillIn; mFillIn = ((mFillIn + 1) % NUM_FRAMES_IN_BUFFER); // Check that we are trying to process a frame different from the // last one processed (useful if this class was running asynchronously) if (mCurrProcessFrameIdx != mLastProcessFrameIdx) { mLastProcessFrameIdx = mCurrProcessFrameIdx; // Access the timestamp associated with it... long timestamp = mFrameTimestamp[mCurrProcessFrameIdx]; // TODO: make the termination condition regarding reaching // MAX_NUMBER_OF_FRAMES solely determined in the library. if (mTotalFrameCount < MAX_NUMBER_OF_FRAMES) { // If we are still collecting new frames for the current mosaic, // process the new frame. calculateTranslationRate(timestamp,prebyte); // Publish progress of the ongoing processing if (mProgressListener != null) { mProgressListener.onProgress(false, mPanningRateX, mPanningRateY, mTranslationLastX * HR_TO_LR_DOWNSAMPLE_FACTOR / mPreviewWidth, mTranslationLastY * HR_TO_LR_DOWNSAMPLE_FACTOR / mPreviewHeight); } } else { if (mProgressListener != null) { mProgressListener.onProgress(true, mPanningRateX, mPanningRateY, mTranslationLastX * HR_TO_LR_DOWNSAMPLE_FACTOR / mPreviewWidth, mTranslationLastY * HR_TO_LR_DOWNSAMPLE_FACTOR / mPreviewHeight); } } } } public void processFrame(byte[] prebyte,byte[] prebyte_ ) { // Log.e(TAG, "processFrame ++++++++++++ --------------------"); // Log.e(TAG, "mTotalFrameCount="+mTotalFrameCount); // Log.e(TAG, "mIsMosaicMemoryAllocated="+mIsMosaicMemoryAllocated); // Log.e(TAG, "mCurrProcessFrameIdx="+mCurrProcessFrameIdx); // Log.e(TAG, "mLastProcessFrameIdx="+mLastProcessFrameIdx); if (!mIsMosaicMemoryAllocated) { // clear() is called and buffers are cleared, stop computation. // This can happen when the onPause() is called in the activity, but still some frames // are not processed yet and thus the callback may be invoked. return; } long t1 = System.currentTimeMillis(); mFrameTimestamp[mFillIn] = t1; mCurrProcessFrameIdx = mFillIn; mFillIn = ((mFillIn + 1) % NUM_FRAMES_IN_BUFFER); // Check that we are trying to process a frame different from the // last one processed (useful if this class was running asynchronously) if (mCurrProcessFrameIdx != mLastProcessFrameIdx) { mLastProcessFrameIdx = mCurrProcessFrameIdx; // Access the timestamp associated with it... long timestamp = mFrameTimestamp[mCurrProcessFrameIdx]; // TODO: make the termination condition regarding reaching // MAX_NUMBER_OF_FRAMES solely determined in the library. if (mTotalFrameCount < MAX_NUMBER_OF_FRAMES) { // If we are still collecting new frames for the current mosaic, // process the new frame. calculateTranslationRate(timestamp,prebyte,prebyte_); // Publish progress of the ongoing processing if (mProgressListener != null) { mProgressListener.onProgress(false, mPanningRateX, mPanningRateY, mTranslationLastX * HR_TO_LR_DOWNSAMPLE_FACTOR / mPreviewWidth, mTranslationLastY * HR_TO_LR_DOWNSAMPLE_FACTOR / mPreviewHeight); } } else { if (mProgressListener != null) { mProgressListener.onProgress(true, mPanningRateX, mPanningRateY, mTranslationLastX * HR_TO_LR_DOWNSAMPLE_FACTOR / mPreviewWidth, mTranslationLastY * HR_TO_LR_DOWNSAMPLE_FACTOR / mPreviewHeight); } } } } public void calculateTranslationRate(long now,byte[] prebyte,byte[] prebyte_) { // Log.e("++++++++++++++++++++++", "ok"); float[] frameData = mMosaicer.setSourceImage3D(prebyte,prebyte_); // Log.e("________________________", "ok"); // Log.e("setSourceImage ̎��mosaic��id ", ""+mMosaicer); int ret_code = (int) frameData[MOSAIC_RET_CODE_INDEX]; mTotalFrameCount = (int) frameData[FRAME_COUNT_INDEX]; float translationCurrX = frameData[X_COORD_INDEX]; float translationCurrY = frameData[Y_COORD_INDEX]; if(CSStaticData.DEBUG) Log.e("frame changdu +++++++++++", "="+frameData[9]); curframe=(int) frameData[9]; if (mLastProcessedFrameTimestamp == 0f) { // First time: no need to update delta values. mTranslationLastX = translationCurrX; mTranslationLastY = translationCurrY; mLastProcessedFrameTimestamp = now; return; } // Moving average: remove the oldest translation/deltaTime and // add the newest translation/deltaTime in int idx = mOldestIdx; mTotalTranslationX -= mDeltaX[idx]; mTotalTranslationY -= mDeltaY[idx]; mTotalDeltaTime -= mDeltaTime[idx]; mDeltaX[idx] = Math.abs(translationCurrX - mTranslationLastX); mDeltaY[idx] = Math.abs(translationCurrY - mTranslationLastY); mDeltaTime[idx] = (now - mLastProcessedFrameTimestamp) / 1000.0f; mTotalTranslationX += mDeltaX[idx]; mTotalTranslationY += mDeltaY[idx]; mTotalDeltaTime += mDeltaTime[idx]; // The panning rate is measured as the rate of the translation percentage in // image width/height. Take the horizontal panning rate for example, the image width // used in finding the translation is (PreviewWidth / HR_TO_LR_DOWNSAMPLE_FACTOR). // To get the horizontal translation percentage, the horizontal translation, // (translationCurrX - mTranslationLastX), is divided by the // image width. We then get the rate by dividing the translation percentage with deltaTime. mPanningRateX = mTotalTranslationX / (mPreviewWidth / HR_TO_LR_DOWNSAMPLE_FACTOR) / mTotalDeltaTime; mPanningRateY = mTotalTranslationY / (mPreviewHeight / HR_TO_LR_DOWNSAMPLE_FACTOR) / mTotalDeltaTime; mTranslationLastX = translationCurrX; mTranslationLastY = translationCurrY; mLastProcessedFrameTimestamp = now; mOldestIdx = (mOldestIdx + 1) % WINDOW_SIZE; } public void calculateTranslationRate(long now,byte[] prebyte) { float[] frameData = mMosaicer.setSourceImage(prebyte); int ret_code = (int) frameData[MOSAIC_RET_CODE_INDEX]; mTotalFrameCount = (int) frameData[FRAME_COUNT_INDEX]; float translationCurrX = frameData[X_COORD_INDEX]; float translationCurrY = frameData[Y_COORD_INDEX]; curframe=(int) frameData[9]; if (mLastProcessedFrameTimestamp == 0f) { // First time: no need to update delta values. mTranslationLastX = translationCurrX; mTranslationLastY = translationCurrY; mLastProcessedFrameTimestamp = now; return; } // Moving average: remove the oldest translation/deltaTime and // add the newest translation/deltaTime in int idx = mOldestIdx; mTotalTranslationX -= mDeltaX[idx]; mTotalTranslationY -= mDeltaY[idx]; mTotalDeltaTime -= mDeltaTime[idx]; mDeltaX[idx] = Math.abs(translationCurrX - mTranslationLastX); mDeltaY[idx] = Math.abs(translationCurrY - mTranslationLastY); mDeltaTime[idx] = (now - mLastProcessedFrameTimestamp) / 1000.0f; mTotalTranslationX += mDeltaX[idx]; mTotalTranslationY += mDeltaY[idx]; mTotalDeltaTime += mDeltaTime[idx]; // The panning rate is measured as the rate of the translation percentage in // image width/height. Take the horizontal panning rate for example, the image width // used in finding the translation is (PreviewWidth / HR_TO_LR_DOWNSAMPLE_FACTOR). // To get the horizontal translation percentage, the horizontal translation, // (translationCurrX - mTranslationLastX), is divided by the // image width. We then get the rate by dividing the translation percentage with deltaTime. mPanningRateX = mTotalTranslationX / (mPreviewWidth / HR_TO_LR_DOWNSAMPLE_FACTOR) / mTotalDeltaTime; mPanningRateY = mTotalTranslationY / (mPreviewHeight / HR_TO_LR_DOWNSAMPLE_FACTOR) / mTotalDeltaTime; mTranslationLastX = translationCurrX; mTranslationLastY = translationCurrY; mLastProcessedFrameTimestamp = now; mOldestIdx = (mOldestIdx + 1) % WINDOW_SIZE; } public void calculateTranslationRate(long now) { float[] frameData = mMosaicer.setSourceImageFromGPU(); int ret_code = (int) frameData[MOSAIC_RET_CODE_INDEX]; mTotalFrameCount = (int) frameData[FRAME_COUNT_INDEX]; float translationCurrX = frameData[X_COORD_INDEX]; float translationCurrY = frameData[Y_COORD_INDEX]; if(CSStaticData.DEBUG) Log.e("frame changdu +++++++++++", "="+frameData[9]); curframe=(int) frameData[9]; if (mLastProcessedFrameTimestamp == 0f) { // First time: no need to update delta values. mTranslationLastX = translationCurrX; mTranslationLastY = translationCurrY; mLastProcessedFrameTimestamp = now; return; } // Moving average: remove the oldest translation/deltaTime and // add the newest translation/deltaTime in int idx = mOldestIdx; mTotalTranslationX -= mDeltaX[idx]; mTotalTranslationY -= mDeltaY[idx]; mTotalDeltaTime -= mDeltaTime[idx]; mDeltaX[idx] = Math.abs(translationCurrX - mTranslationLastX); mDeltaY[idx] = Math.abs(translationCurrY - mTranslationLastY); mDeltaTime[idx] = (now - mLastProcessedFrameTimestamp) / 1000.0f; mTotalTranslationX += mDeltaX[idx]; mTotalTranslationY += mDeltaY[idx]; mTotalDeltaTime += mDeltaTime[idx]; // The panning rate is measured as the rate of the translation percentage in // image width/height. Take the horizontal panning rate for example, the image width // used in finding the translation is (PreviewWidth / HR_TO_LR_DOWNSAMPLE_FACTOR). // To get the horizontal translation percentage, the horizontal translation, // (translationCurrX - mTranslationLastX), is divided by the // image width. We then get the rate by dividing the translation percentage with deltaTime. mPanningRateX = mTotalTranslationX / (mPreviewWidth / HR_TO_LR_DOWNSAMPLE_FACTOR) / mTotalDeltaTime; mPanningRateY = mTotalTranslationY / (mPreviewHeight / HR_TO_LR_DOWNSAMPLE_FACTOR) / mTotalDeltaTime; mTranslationLastX = translationCurrX; mTranslationLastY = translationCurrY; mLastProcessedFrameTimestamp = now; mOldestIdx = (mOldestIdx + 1) % WINDOW_SIZE; } }