diff options
Diffstat (limited to 'src/com/android/camera')
-rw-r--r-- | src/com/android/camera/Camera.java | 4 | ||||
-rw-r--r-- | src/com/android/camera/FaceListener.java | 20 | ||||
-rw-r--r-- | src/com/android/camera/panorama/Mosaic.java | 14 | ||||
-rw-r--r-- | src/com/android/camera/panorama/MosaicFrameProcessor.java | 21 | ||||
-rw-r--r-- | src/com/android/camera/panorama/MosaicRenderer.java | 34 | ||||
-rw-r--r-- | src/com/android/camera/panorama/MosaicRendererSurfaceView.java | 78 | ||||
-rw-r--r-- | src/com/android/camera/panorama/MosaicRendererSurfaceViewRenderer.java | 67 | ||||
-rw-r--r-- | src/com/android/camera/panorama/PanoramaActivity.java | 193 |
8 files changed, 330 insertions, 101 deletions
diff --git a/src/com/android/camera/Camera.java b/src/com/android/camera/Camera.java index 86ab4e9..ae883b8 100644 --- a/src/com/android/camera/Camera.java +++ b/src/com/android/camera/Camera.java @@ -529,6 +529,7 @@ public class Camera extends ActivityBase implements View.OnClickListener, if (mParameters.getMaxNumDetectedFaces() > 0) { mCameraDevice.setFaceDetectionListener(null); mCameraDevice.stopFaceDetection(); + if (mFaceListener != null) mFaceListener.clearFaces(); } } @@ -1520,6 +1521,9 @@ public class Camera extends ActivityBase implements View.OnClickListener, } private void updateFocusUI() { + // Do not show focus rectangle if there is any face rectangle. + if (mFaceListener != null && mFaceListener.faceExists()) return; + if (mCameraState == FOCUSING || mCameraState == FOCUSING_SNAP_ON_FINISH) { mFocusRectangle.showStart(); } else if (mCameraState == FOCUS_SUCCESS) { diff --git a/src/com/android/camera/FaceListener.java b/src/com/android/camera/FaceListener.java index 87d9ec1..dae0bda 100644 --- a/src/com/android/camera/FaceListener.java +++ b/src/com/android/camera/FaceListener.java @@ -64,10 +64,24 @@ class FaceListener implements android.hardware.Camera.FaceDetectionListener { if (LOGV) Log.v(TAG, "mMirror=" + mirror); } + public boolean faceExists() { + if (mFaces[0] == null) return false; + if (mFaces[0].getVisibility() == View.VISIBLE) { + return true; + } else { + return false; + } + } + + public void clearFaces() { + for (int i = 0; i < MAX_NUM_FACES; i++) { + if (mFaces[i] == null) break; + if (mFaces[i].getVisibility() != View.VISIBLE) break; + mFaces[i].setVisibility(View.GONE); + } + } + private void showFaces(Face[] faces) { - // The range of the coordinates from the driver is -1000 to 1000. - // So the maximum length of the width or height is 2000. We need to - // convert them to UI layout size later. for (int i = 0; i < MAX_NUM_FACES; i++) { if (i < faces.length) { // Inflate the view if it's not done yet. diff --git a/src/com/android/camera/panorama/Mosaic.java b/src/com/android/camera/panorama/Mosaic.java index 5012ff4..80e8263 100644 --- a/src/com/android/camera/panorama/Mosaic.java +++ b/src/com/android/camera/panorama/Mosaic.java @@ -99,6 +99,20 @@ public class Mosaic { public native float[] setSourceImage(byte[] pixels); /** + * This is an alternative to the setSourceImage function above. This should + * be called when the image data is already on the native side in a fixed + * byte array. In implementation, this array is filled by the GL thread + * using glReadPixels directly from GPU memory (where it is accessed by + * an associated SurfaceTexture). + * + * @return Float array of length 10; first 9 entries correspond to the 3x3 + * transformation matrix between the first frame and the passed frame, + * and the last entry is the number of the passed frame, + * where the counting starts from 1. + */ + public native float[] setSourceImageFromGPU(); + + /** * Set the type of blending. * * @param type the blending type defined in the class. {BLENDTYPE_FULL, diff --git a/src/com/android/camera/panorama/MosaicFrameProcessor.java b/src/com/android/camera/panorama/MosaicFrameProcessor.java index 6496f11..502d41f 100644 --- a/src/com/android/camera/panorama/MosaicFrameProcessor.java +++ b/src/com/android/camera/panorama/MosaicFrameProcessor.java @@ -56,18 +56,20 @@ public class MosaicFrameProcessor { private int mPreviewWidth; private int mPreviewHeight; private int mPreviewBufferSize; + private boolean mUseSurfaceTexture; public interface ProgressListener { public void onProgress(boolean isFinished, float translationRate, int traversedAngleX, int traversedAngleY); } - public MosaicFrameProcessor(int sweepAngle, int previewWidth, int previewHeight, int bufSize) { + public MosaicFrameProcessor(int sweepAngle, int previewWidth, int previewHeight, int bufSize, boolean useSurfaceTexture) { mMosaicer = new Mosaic(); mCompassThreshold = sweepAngle; mPreviewWidth = previewWidth; mPreviewHeight = previewHeight; mPreviewBufferSize = bufSize; + mUseSurfaceTexture = useSurfaceTexture; } public void setProgressListener(ProgressListener listener) { @@ -75,7 +77,7 @@ public class MosaicFrameProcessor { } public void initialize() { - setupMosaicer(mPreviewWidth, mPreviewHeight, mPreviewBufferSize); + setupMosaicer(mPreviewWidth, mPreviewHeight, mPreviewBufferSize, mUseSurfaceTexture); reset(); } @@ -87,8 +89,7 @@ public class MosaicFrameProcessor { } } - - private void setupMosaicer(int previewWidth, int previewHeight, int bufSize) { + private void setupMosaicer(int previewWidth, int previewHeight, int bufSize, boolean useSurfaceTexture) { Log.v(TAG, "setupMosaicer w, h=" + previewWidth + ',' + previewHeight + ',' + bufSize); mMosaicer.allocateMosaicMemory(previewWidth, previewHeight); @@ -133,11 +134,14 @@ public class MosaicFrameProcessor { } long t1 = System.currentTimeMillis(); mFrameTimestamp[mFillIn] = t1; - System.arraycopy(data, 0, mFrames[mFillIn], 0, data.length); + + // TODO: Remove the case of byte data copy when SurfaceTexture is ready + if(!mUseSurfaceTexture) + System.arraycopy(data, 0, mFrames[mFillIn], 0, data.length); + 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) { @@ -184,11 +188,12 @@ public class MosaicFrameProcessor { float deltaTime = (now - mLastProcessedFrameTimestamp) / 1000.0f; mLastProcessedFrameTimestamp = now; - float[] frameData = mMosaicer.setSourceImage(data); + float[] frameData = mUseSurfaceTexture ? + mMosaicer.setSourceImageFromGPU() : + mMosaicer.setSourceImage(data); mTotalFrameCount = (int) frameData[FRAME_COUNT_INDEX]; float translationCurrX = frameData[X_COORD_INDEX]; float translationCurrY = frameData[Y_COORD_INDEX]; - mTranslationRate = Math.max(Math.abs(translationCurrX - mTranslationLastX), Math.abs(translationCurrY - mTranslationLastY)) / deltaTime; mTranslationLastX = translationCurrX; diff --git a/src/com/android/camera/panorama/MosaicRenderer.java b/src/com/android/camera/panorama/MosaicRenderer.java index 8db95c0..2bf471c 100644 --- a/src/com/android/camera/panorama/MosaicRenderer.java +++ b/src/com/android/camera/panorama/MosaicRenderer.java @@ -30,9 +30,12 @@ public class MosaicRenderer /** * Function to be called in onSurfaceCreated() to initialize * the GL context, load and link the shaders and create the - * program. + * program. Returns a texture ID to be used for SurfaceTexture. + * + * @return textureID the texture ID of the newly generated texture to + * be assigned to the SurfaceTexture object. */ - public static native void init(); + public static native int init(); /** * Pass the drawing surface's width and height to initialize the @@ -44,6 +47,23 @@ public class MosaicRenderer public static native void reset(int width, int height); /** + * Calling this function will render the SurfaceTexture to a new 2D texture + * using the provided STMatrix and then call glReadPixels to fill the data + * array that will be processed by the mosaicing thread. + * + * @param stMatrix texture coordinate transform matrix obtained from the + * Surface texture + */ + public static native void preprocess(float[] stMatrix); + + /** + * This function calls glReadPixels to transfer both the low-res and high-res + * data from the GPU memory to the CPU memory for further processing by the + * mosaicing library. + */ + public static native void transferGPUtoCPU(); + + /** * Function to be called in onDrawFrame() to update the screen with * the new frame data. */ @@ -59,9 +79,11 @@ public class MosaicRenderer /** * This function allows toggling between showing the input image data - * (without applying any warp) and the warped image data. This is more - * for debugging purposes to see if the image data is being updated - * correctly or not. + * (without applying any warp) and the warped image data. For running + * the renderer as a viewfinder, we set the flag to false. To see the + * preview mosaic, we set the flag to true. + * + * @param flag boolean flag to set the warping to true or false. */ - public static native void togglewarping(); + public static native void setWarping(boolean flag); } diff --git a/src/com/android/camera/panorama/MosaicRendererSurfaceView.java b/src/com/android/camera/panorama/MosaicRendererSurfaceView.java index 3220b22..6767c87 100644 --- a/src/com/android/camera/panorama/MosaicRendererSurfaceView.java +++ b/src/com/android/camera/panorama/MosaicRendererSurfaceView.java @@ -21,9 +21,12 @@ import javax.microedition.khronos.egl.EGLConfig; import javax.microedition.khronos.egl.EGLContext; import javax.microedition.khronos.egl.EGLDisplay; +import android.app.Activity; import android.content.Context; import android.graphics.PixelFormat; +import android.graphics.SurfaceTexture; import android.opengl.GLSurfaceView; +import android.os.ConditionVariable; import android.util.AttributeSet; import android.util.Log; @@ -31,6 +34,7 @@ public class MosaicRendererSurfaceView extends GLSurfaceView { private static String TAG = "MosaicRendererSurfaceView"; private static final boolean DEBUG = false; private MosaicRendererSurfaceViewRenderer mRenderer; + private ConditionVariable mPreviewFrameReadyForProcessing; public MosaicRendererSurfaceView(Context context) { super(context); @@ -50,7 +54,6 @@ public class MosaicRendererSurfaceView extends GLSurfaceView { setZOrderMediaOverlay(true); } - private void init(boolean translucent, int depth, int stencil) { /* By default, GLSurfaceView() creates a RGB_565 opaque surface. @@ -80,6 +83,7 @@ public class MosaicRendererSurfaceView extends GLSurfaceView { mRenderer = new MosaicRendererSurfaceViewRenderer(); setRenderer(mRenderer); setRenderMode(RENDERMODE_WHEN_DIRTY); + mPreviewFrameReadyForProcessing = new ConditionVariable(); } private static class ContextFactory implements GLSurfaceView.EGLContextFactory { @@ -298,6 +302,21 @@ public class MosaicRendererSurfaceView extends GLSurfaceView { private int[] mValue = new int[1]; } + public void lockPreviewReadyFlag() + { + mPreviewFrameReadyForProcessing.close(); + } + + private void unlockPreviewReadyFlag() + { + mPreviewFrameReadyForProcessing.open(); + } + + public void waitUntilPreviewReady() + { + mPreviewFrameReadyForProcessing.block(); + } + public void setReady() { queueEvent(new Runnable() { @@ -309,14 +328,67 @@ public class MosaicRendererSurfaceView extends GLSurfaceView { }); } - public void toggleWarping() + public void preprocess() + { + queueEvent(new Runnable() { + + @Override + public void run() { + mRenderer.preprocess(); + } + }); + } + + public void transferGPUtoCPU() + { + queueEvent(new Runnable() { + + @Override + public void run() { + mRenderer.transferGPUtoCPU(); + unlockPreviewReadyFlag(); + } + }); + } + + public void setUIObject(final Activity activity) { queueEvent(new Runnable() { @Override public void run() { - mRenderer.toggleWarping(); + mRenderer.setUIObject(activity); } }); } + + public void setWarping(final boolean flag) + { + queueEvent(new Runnable() { + + @Override + public void run() { + mRenderer.setWarping(flag); + } + }); + } + + public int getTextureID() { + return mRenderer.getTextureID(); + } + + public void setSurfaceTexture(SurfaceTexture surface) { + mRenderer.setSurfaceTexture(surface); + } + + public void updateSurfaceTexture() { + queueEvent(new Runnable() { + + @Override + public void run() { + mRenderer.updateSurfaceTexture(); + } + }); + } + } diff --git a/src/com/android/camera/panorama/MosaicRendererSurfaceViewRenderer.java b/src/com/android/camera/panorama/MosaicRendererSurfaceViewRenderer.java index a27d4be..d29765a 100644 --- a/src/com/android/camera/panorama/MosaicRendererSurfaceViewRenderer.java +++ b/src/com/android/camera/panorama/MosaicRendererSurfaceViewRenderer.java @@ -19,37 +19,78 @@ package com.android.camera.panorama; import javax.microedition.khronos.egl.EGLConfig; import javax.microedition.khronos.opengles.GL10; +import android.app.Activity; +import android.graphics.SurfaceTexture; import android.opengl.GLSurfaceView; - +import android.util.Log; public class MosaicRendererSurfaceViewRenderer implements GLSurfaceView.Renderer { @Override - public void onDrawFrame(GL10 gl) - { + public void onDrawFrame(GL10 gl) { MosaicRenderer.step(); } @Override - public void onSurfaceChanged(GL10 gl, int width, int height) - { + public void onSurfaceChanged(GL10 gl, int width, int height) { + Log.i(TAG, "Renderer: onSurfaceChanged"); MosaicRenderer.reset(width, height); + Log.i(TAG, "Renderer: onSurfaceChanged"); } @Override - public void onSurfaceCreated(GL10 gl, EGLConfig config) - { - MosaicRenderer.init(); + public void onSurfaceCreated(GL10 gl, EGLConfig config) { + mTextureID = MosaicRenderer.init(); + + mActivity.runOnUiThread(new Runnable() { + + @Override + public void run() { + mActivity.createSurfaceTextureAndStartPreview(mTextureID); + setSurfaceTexture(mActivity.getSurfaceTexture()); + } + }); } - public void setReady() - { + public void setReady() { MosaicRenderer.ready(); } - public void toggleWarping() - { - MosaicRenderer.togglewarping(); + public void preprocess() { + MosaicRenderer.preprocess(mSTMatrix); + } + + public void transferGPUtoCPU() { + MosaicRenderer.transferGPUtoCPU(); + } + + public void setWarping(boolean flag) { + MosaicRenderer.setWarping(flag); + } + + public void updateSurfaceTexture() { + mSurface.updateTexImage(); + mSurface.getTransformMatrix(mSTMatrix); } + public void setUIObject(Activity activity) { + mActivity = (PanoramaActivity)activity; + } + + public int getTextureID() { + return mTextureID; + } + + public void setSurfaceTexture(SurfaceTexture surface) { + mSurface = surface; + } + + private float[] mSTMatrix = new float[16]; + private int mTextureID; + + private PanoramaActivity mActivity; + + private static String TAG = "MosaicRendererSurfaceViewRenderer"; + + private SurfaceTexture mSurface; } diff --git a/src/com/android/camera/panorama/PanoramaActivity.java b/src/com/android/camera/panorama/PanoramaActivity.java index 0b1ec60..d9645ff 100644 --- a/src/com/android/camera/panorama/PanoramaActivity.java +++ b/src/com/android/camera/panorama/PanoramaActivity.java @@ -33,19 +33,19 @@ import android.graphics.BitmapFactory; import android.graphics.ImageFormat; import android.graphics.PixelFormat; import android.graphics.Rect; +import android.graphics.SurfaceTexture; import android.graphics.YuvImage; import android.hardware.Camera; -import android.hardware.Camera.Parameters; -import android.hardware.Camera.Size; import android.hardware.Sensor; import android.hardware.SensorEvent; import android.hardware.SensorEventListener; import android.hardware.SensorManager; +import android.hardware.Camera.Parameters; +import android.hardware.Camera.Size; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.util.Log; -import android.view.SurfaceHolder; import android.view.SurfaceView; import android.view.View; import android.view.WindowManager; @@ -58,7 +58,8 @@ import java.util.List; * Activity to handle panorama capturing. */ public class PanoramaActivity extends Activity implements - ModePicker.OnModeChangeListener, SurfaceHolder.Callback { + ModePicker.OnModeChangeListener, + SurfaceTexture.OnFrameAvailableListener { public static final int DEFAULT_SWEEP_ANGLE = 60; public static final int DEFAULT_BLEND_MODE = Mosaic.BLENDTYPE_HORIZONTAL; public static final int DEFAULT_CAPTURE_PIXELS = 960 * 720; @@ -69,6 +70,9 @@ public class PanoramaActivity extends Activity implements private static final String TAG = "PanoramaActivity"; private static final int PREVIEW_STOPPED = 0; private static final int PREVIEW_ACTIVE = 1; + private static final int CAPTURE_VIEWFINDER = 0; + private static final int CAPTURE_MOSAIC = 1; + // Ratio of nanosecond to second private static final float NS2S = 1.0f / 1000000000.0f; @@ -89,6 +93,7 @@ public class PanoramaActivity extends Activity implements private int mPreviewHeight; private Camera mCameraDevice; private int mCameraState; + private int mCaptureState; private SensorManager mSensorManager; private Sensor mSensor; private ModePicker mModePicker; @@ -96,7 +101,8 @@ public class PanoramaActivity extends Activity implements private String mCurrentImagePath = null; private long mTimeTaken; private Handler mMainHandler; - private SurfaceHolder mSurfaceHolder; + private SurfaceTexture mSurface; + private boolean mUseSurfaceTexture = true; private boolean mThreadRunning; @@ -133,6 +139,22 @@ public class PanoramaActivity extends Activity implements }; } + public void createSurfaceTextureAndStartPreview(int textureID) + { + /* + * Create the SurfaceTexture that will feed this textureID, and pass it to the camera + */ + mSurface = new SurfaceTexture(textureID); + mSurface.setOnFrameAvailableListener(this); + startPreview(); + Log.i(TAG, "Created Surface Texture"); + } + + public SurfaceTexture getSurfaceTexture() + { + return mSurface; + } + private void setupCamera() { openCamera(); Parameters parameters = mCameraDevice.getParameters(); @@ -223,14 +245,16 @@ public class PanoramaActivity extends Activity implements CameraHolder.instance().getBackCameraId()); mCameraDevice.setDisplayOrientation(orientation); - int bufSize = getPreviewBufSize(); - Log.v(TAG, "BufSize = " + bufSize); - for (int i = 0; i < 10; i++) { - try { - mCameraDevice.addCallbackBuffer(new byte[bufSize]); - } catch (OutOfMemoryError e) { - Log.v(TAG, "Buffer allocation failed: buffer " + i); - break; + if(!mUseSurfaceTexture) { + int bufSize = getPreviewBufSize(); + Log.v(TAG, "BufSize = " + bufSize); + for (int i = 0; i < 10; i++) { + try { + mCameraDevice.addCallbackBuffer(new byte[bufSize]); + } catch (OutOfMemoryError e) { + Log.v(TAG, "Buffer allocation failed: buffer " + i); + break; + } } } } @@ -252,9 +276,51 @@ public class PanoramaActivity extends Activity implements } } + public void runViewFinder() { + mRealTimeMosaicView.setWarping(false); + + // First update the surface texture... + mRealTimeMosaicView.updateSurfaceTexture(); + // ...then call preprocess to render it to low-res and high-res RGB textures + mRealTimeMosaicView.preprocess(); + + mRealTimeMosaicView.setReady(); + mRealTimeMosaicView.requestRender(); + } + + public void runMosaicCapture() { + mRealTimeMosaicView.setWarping(true); + + // Lock the condition variable + mRealTimeMosaicView.lockPreviewReadyFlag(); + // First update the surface texture... + mRealTimeMosaicView.updateSurfaceTexture(); + // ...then call preprocess to render it to low-res and high-res RGB textures + mRealTimeMosaicView.preprocess(); + // Now, transfer the textures from GPU to CPU memory for processing + mRealTimeMosaicView.transferGPUtoCPU(); + // Wait on the condition variable (will be opened when GPU->CPU transfer is done). + mRealTimeMosaicView.waitUntilPreviewReady(); + + mMosaicFrameProcessor.processFrame(null); + } + + synchronized public void onFrameAvailable(SurfaceTexture surface) { + /* For simplicity, SurfaceTexture calls here when it has new + * data available. Call may come in from some random thread, + * so let's be safe and use synchronize. No OpenGL calls can be done here. + */ + if (mCaptureState == CAPTURE_VIEWFINDER) { + runViewFinder(); + } else { + runMosaicCapture(); + } + } + public void startCapture() { // Reset values so we can do this again. mTimeTaken = System.currentTimeMillis(); + mCaptureState = CAPTURE_MOSAIC; mMosaicFrameProcessor.setProgressListener(new MosaicFrameProcessor.ProgressListener() { @Override @@ -268,26 +334,38 @@ public class PanoramaActivity extends Activity implements } }); - // Preview callback used whenever new viewfinder frame is available - mCameraDevice.setPreviewCallbackWithBuffer(new Camera.PreviewCallback() { - @Override - public void onPreviewFrame(final byte[] data, Camera camera) { - mMosaicFrameProcessor.processFrame(data); - // The returned buffer needs be added back to callback buffer - // again. - camera.addCallbackBuffer(data); - } - }); + if (!mUseSurfaceTexture) { + // Preview callback used whenever new viewfinder frame is available + mCameraDevice.setPreviewCallbackWithBuffer(new Camera.PreviewCallback() { + @Override + public void onPreviewFrame(final byte[] data, Camera camera) { + mMosaicFrameProcessor.processFrame(data); + // The returned buffer needs be added back to callback buffer + // again. + camera.addCallbackBuffer(data); + } + }); + } mCaptureLayout.setVisibility(View.VISIBLE); mPreview.setVisibility(View.INVISIBLE); // will be re-used, invisible is better than gone. mRealTimeMosaicView.setVisibility(View.VISIBLE); mPanoControlLayout.setVisibility(View.GONE); + } private void stopCapture() { + mCaptureState = CAPTURE_VIEWFINDER; + mMosaicFrameProcessor.setProgressListener(null); stopPreview(); + + if (!mUseSurfaceTexture) { + mCameraDevice.setPreviewCallbackWithBuffer(null); + } + + mSurface.setOnFrameAvailableListener(null); + // TODO: show some dialog for long computation. if (!mThreadRunning) { mThreadRunning = true; @@ -322,17 +400,19 @@ public class PanoramaActivity extends Activity implements private void createContentView() { setContentView(R.layout.panorama); + mCaptureState = CAPTURE_VIEWFINDER; + mCaptureLayout = (View) findViewById(R.id.pano_capture_layout); mReviewLayout = (View) findViewById(R.id.pano_review_layout); mPreview = (SurfaceView) findViewById(R.id.pano_preview_view); - mPreview.getHolder().addCallback(this); + mCaptureView = (CaptureView) findViewById(R.id.pano_capture_view); mCaptureView.setStartAngle(-DEFAULT_SWEEP_ANGLE / 2); mReview = (ImageView) findViewById(R.id.pano_reviewarea); mRealTimeMosaicView = (MosaicRendererSurfaceView) findViewById(R.id.pano_renderer); - mRealTimeMosaicView.setVisibility(View.GONE); + mRealTimeMosaicView.setUIObject(this); mShutterButton = (ShutterButton) findViewById(R.id.pano_shutter_button); mShutterButton.setOnClickListener(new View.OnClickListener() { @@ -349,6 +429,8 @@ public class PanoramaActivity extends Activity implements mModePicker.setVisibility(View.VISIBLE); mModePicker.setOnModeChangeListener(this); mModePicker.setCurrentMode(ModePicker.MODE_PANORAMA); + + mRealTimeMosaicView.setVisibility(View.VISIBLE); } @OnClickAttr @@ -377,13 +459,19 @@ public class PanoramaActivity extends Activity implements } private void resetToPreview() { + mCaptureState = CAPTURE_VIEWFINDER; + + mReviewLayout.setVisibility(View.GONE); mPreview.setVisibility(View.VISIBLE); mPanoControlLayout.setVisibility(View.VISIBLE); - mRealTimeMosaicView.setVisibility(View.GONE); mCaptureLayout.setVisibility(View.GONE); - mReviewLayout.setVisibility(View.GONE); mMosaicFrameProcessor.reset(); + + mSurface.setOnFrameAvailableListener(this); + if (!mPausing) startPreview(); + + mRealTimeMosaicView.setVisibility(View.VISIBLE); } private void showFinalMosaic(Bitmap bitmap) { @@ -394,6 +482,7 @@ public class PanoramaActivity extends Activity implements mReviewLayout.setVisibility(View.VISIBLE); mCaptureView.setStatusText(""); mCaptureView.setSweepAngle(0); + mCaptureView.invalidate(); } } @@ -416,7 +505,7 @@ public class PanoramaActivity extends Activity implements if (mMosaicFrameProcessor == null) { // Start the activity for the first time. mMosaicFrameProcessor = new MosaicFrameProcessor(DEFAULT_SWEEP_ANGLE - 5, - mPreviewWidth, mPreviewHeight, getPreviewBufSize()); + mPreviewWidth, mPreviewHeight, getPreviewBufSize(), mUseSurfaceTexture); } mMosaicFrameProcessor.initialize(); } @@ -424,10 +513,12 @@ public class PanoramaActivity extends Activity implements @Override protected void onPause() { super.onPause(); + mSurface.setOnFrameAvailableListener(null); releaseCamera(); mPausing = true; - mCaptureView.onPause(); + mRealTimeMosaicView.onPause(); + mCaptureView.onPause(); mSensorManager.unregisterListener(mListener); clearMosaicFrameProcessorIfNeeded(); System.gc(); @@ -446,12 +537,11 @@ public class PanoramaActivity extends Activity implements * resources. */ mSensorManager.registerListener(mListener, mSensor, SensorManager.SENSOR_DELAY_UI); - + mCaptureState = CAPTURE_VIEWFINDER; setupCamera(); // Camera must be initialized before MosaicFrameProcessor is initialized. The preview size // has to be decided by camera device. initMosaicFrameProcessorIfNeeded(); - startPreview(); mCaptureView.onResume(); mRealTimeMosaicView.onResume(); } @@ -526,45 +616,12 @@ public class PanoramaActivity extends Activity implements System.gc(); } - @Override - public void surfaceCreated(SurfaceHolder holder) { - } - - @Override - public void surfaceDestroyed(SurfaceHolder holder) { - } - - @Override - public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) { - mSurfaceHolder = holder; - - if (mCameraDevice == null) return; - - // Set preview display if the surface is being created. Preview was - // already started. Also restart the preview if display rotation has - // changed. Sometimes this happens when the device is held in portrait - // and camera app is opened. Rotation animation takes some time and - // display rotation in onCreate may not be what we want. - if (holder.isCreating()) { - // Set preview display if the surface is being created and preview - // was already started. That means preview display was set to null - // and we need to set it now. - setPreviewDisplay(holder); - } else { - // 1. Restart the preview if the size of surface was changed. The - // framework may not support changing preview display on the fly. - // 2. Start the preview now if surface was destroyed and preview - // stopped. - startPreview(); - } - } - - private void setPreviewDisplay(SurfaceHolder holder) { + private void setPreviewTexture(SurfaceTexture surface) { try { - mCameraDevice.setPreviewDisplay(holder); + mCameraDevice.setPreviewTexture(surface); } catch (Throwable ex) { releaseCamera(); - throw new RuntimeException("setPreviewDisplay failed", ex); + throw new RuntimeException("setPreviewTexture failed", ex); } } @@ -573,7 +630,7 @@ public class PanoramaActivity extends Activity implements // the screen). if (mCameraState != PREVIEW_STOPPED) stopPreview(); - setPreviewDisplay(mSurfaceHolder); + setPreviewTexture(mSurface); try { Log.v(TAG, "startPreview"); |