diff options
-rw-r--r-- | jni/feature_mos/src/mosaic/Blend.cpp | 24 | ||||
-rw-r--r-- | jni/feature_mos/src/mosaic/Blend.h | 5 | ||||
-rw-r--r-- | jni/feature_mos/src/mosaic/Mosaic.cpp | 22 | ||||
-rw-r--r-- | jni/feature_mos/src/mosaic/Mosaic.h | 3 | ||||
-rw-r--r-- | jni/feature_mos_jni.cpp | 50 | ||||
-rw-r--r-- | src/com/android/camera/panorama/Mosaic.java | 15 | ||||
-rw-r--r-- | src/com/android/camera/panorama/MosaicFrameProcessor.java | 8 | ||||
-rw-r--r-- | src/com/android/camera/panorama/PanoramaActivity.java | 76 |
8 files changed, 154 insertions, 49 deletions
diff --git a/jni/feature_mos/src/mosaic/Blend.cpp b/jni/feature_mos/src/mosaic/Blend.cpp index ee67d5a..cc146a8 100644 --- a/jni/feature_mos/src/mosaic/Blend.cpp +++ b/jni/feature_mos/src/mosaic/Blend.cpp @@ -91,7 +91,7 @@ void Blend::AlignToMiddleFrame(MosaicFrame **frames, int frames_size) int Blend::runBlend(MosaicFrame **frames, int frames_size, ImageType &imageMosaicYVU, int &mosaicWidth, int &mosaicHeight, - float &progress) + float &progress, bool &cancelComputation) { int ret; int numCenters; @@ -185,7 +185,7 @@ int Blend::runBlend(MosaicFrame **frames, int frames_size, // Do merging and blending : ret = DoMergeAndBlend(frames, numCenters, width, height, *imgMos, fullRect, - cropping_rect, progress); + cropping_rect, progress, cancelComputation); if (m_wb.blendingType == BLEND_TYPE_HORZ) CropFinalMosaic(*imgMos, cropping_rect); @@ -207,7 +207,7 @@ int Blend::runBlend(MosaicFrame **frames, int frames_size, mosaicHeight = Mheight; } - return BLEND_RET_OK; + return ret; } @@ -256,7 +256,7 @@ int Blend::FillFramePyramid(MosaicFrame *mb) int Blend::DoMergeAndBlend(MosaicFrame **frames, int nsite, int width, int height, YUVinfo &imgMos, MosaicRect &rect, - MosaicRect &cropping_rect, float &progress) + MosaicRect &cropping_rect, float &progress, bool &cancelComputation) { m_pMosaicYPyr = NULL; m_pMosaicUPyr = NULL; @@ -280,6 +280,14 @@ int Blend::DoMergeAndBlend(MosaicFrame **frames, int nsite, site_idx = 0; for(CSite *csite = m_AllSites; csite < esite; csite++) { + if(cancelComputation) + { + if (m_pMosaicVPyr) free(m_pMosaicVPyr); + if (m_pMosaicUPyr) free(m_pMosaicUPyr); + if (m_pMosaicYPyr) free(m_pMosaicYPyr); + return BLEND_RET_CANCELLED; + } + mb = csite->getMb(); mb->vcrect = mb->brect; @@ -294,6 +302,14 @@ int Blend::DoMergeAndBlend(MosaicFrame **frames, int nsite, site_idx = 0; for(CSite *csite = m_AllSites; csite < esite; csite++) { + if(cancelComputation) + { + if (m_pMosaicVPyr) free(m_pMosaicVPyr); + if (m_pMosaicUPyr) free(m_pMosaicUPyr); + if (m_pMosaicYPyr) free(m_pMosaicYPyr); + return BLEND_RET_CANCELLED; + } + mb = csite->getMb(); diff --git a/jni/feature_mos/src/mosaic/Blend.h b/jni/feature_mos/src/mosaic/Blend.h index 013fbbf..c878be4 100644 --- a/jni/feature_mos/src/mosaic/Blend.h +++ b/jni/feature_mos/src/mosaic/Blend.h @@ -68,6 +68,7 @@ public: static const int BLEND_RET_ERROR = -1; static const int BLEND_RET_OK = 0; static const int BLEND_RET_ERROR_MEMORY = 1; + static const int BLEND_RET_CANCELLED = -2; Blend(); ~Blend(); @@ -75,7 +76,7 @@ public: int initialize(int blendingType, int frame_width, int frame_height); int runBlend(MosaicFrame **frames, int frames_size, ImageType &imageMosaicYVU, - int &mosaicWidth, int &mosaicHeight, float &progress); + int &mosaicWidth, int &mosaicHeight, float &progress, bool &cancelComputation); protected: @@ -105,7 +106,7 @@ protected: void ClipBlendRect(CSite *csite, BlendRect &brect); void AlignToMiddleFrame(MosaicFrame **frames, int frames_size); - int DoMergeAndBlend(MosaicFrame **frames, int nsite, int width, int height, YUVinfo &imgMos, MosaicRect &rect, MosaicRect &cropping_rect, float &progress); + int DoMergeAndBlend(MosaicFrame **frames, int nsite, int width, int height, YUVinfo &imgMos, MosaicRect &rect, MosaicRect &cropping_rect, float &progress, bool &cancelComputation); void ComputeMask(CSite *csite, BlendRect &vcrect, BlendRect &brect, MosaicRect &rect, YUVinfo &imgMos, int site_idx); void ProcessPyramidForThisFrame(CSite *csite, BlendRect &vcrect, BlendRect &brect, MosaicRect &rect, YUVinfo &imgMos, double trs[3][3], int site_idx); diff --git a/jni/feature_mos/src/mosaic/Mosaic.cpp b/jni/feature_mos/src/mosaic/Mosaic.cpp index 988ec28..3dc1e1d 100644 --- a/jni/feature_mos/src/mosaic/Mosaic.cpp +++ b/jni/feature_mos/src/mosaic/Mosaic.cpp @@ -153,7 +153,7 @@ int Mosaic::addFrame(ImageType imageYVU) } -int Mosaic::createMosaic(float &progress) +int Mosaic::createMosaic(float &progress, bool &cancelComputation) { printf("Creating mosaic\n"); @@ -172,14 +172,28 @@ int Mosaic::createMosaic(float &progress) } + int ret; + // Blend the mosaic (alignment has already been done) if (blender != NULL) { - blender->runBlend((MosaicFrame **) frames, frames_size, imageMosaicYVU, - mosaicWidth, mosaicHeight, progress); + ret = blender->runBlend((MosaicFrame **) frames, frames_size, imageMosaicYVU, + mosaicWidth, mosaicHeight, progress, cancelComputation); } - return MOSAIC_RET_OK; + switch(ret) + { + case Blend::BLEND_RET_ERROR: + case Blend::BLEND_RET_ERROR_MEMORY: + ret = MOSAIC_RET_ERROR; + break; + case Blend::BLEND_RET_CANCELLED: + ret = MOSAIC_RET_CANCELLED; + break; + case Blend::BLEND_RET_OK: + ret = MOSAIC_RET_OK; + } + return ret; } ImageType Mosaic::getMosaic(int &width, int &height) diff --git a/jni/feature_mos/src/mosaic/Mosaic.h b/jni/feature_mos/src/mosaic/Mosaic.h index 25abc43..ecf0536 100644 --- a/jni/feature_mos/src/mosaic/Mosaic.h +++ b/jni/feature_mos/src/mosaic/Mosaic.h @@ -112,7 +112,7 @@ public: * \param progress Variable to set the current progress in. * \return Return code signifying success or failure. */ - int createMosaic(float &progress); + int createMosaic(float &progress, bool &cancelComputation); /*! * Obtains the resulting mosaic and its dimensions. @@ -141,6 +141,7 @@ public: */ static const int MOSAIC_RET_OK = 1; static const int MOSAIC_RET_ERROR = -1; + static const int MOSAIC_RET_CANCELLED = -2; protected: diff --git a/jni/feature_mos_jni.cpp b/jni/feature_mos_jni.cpp index 1c163ab..84647b9 100644 --- a/jni/feature_mos_jni.cpp +++ b/jni/feature_mos_jni.cpp @@ -67,9 +67,10 @@ ImageType resultBGR = ImageUtils::IMAGE_TYPE_NOIMAGE; float gTRS[10]; // Variables to keep track of the mosaic computation progress for both LR & HR. float gProgress[NR]; +// Variables to be able to cancel the mosaic computation when the GUI says so. +bool gCancelComputation[NR]; int c; -int ret; int width=0, height=0; int mosaicWidth=0, mosaicHeight=0; @@ -207,19 +208,21 @@ int AddFrame(int mID, int k, float* trs1d) return ret_code; } -void Finalize(int mID) +int Finalize(int mID) { double t0, t1, time_c; t0 = now_ms(); // Create the mosaic - ret = mosaic[mID]->createMosaic(gProgress[mID]); + int ret = mosaic[mID]->createMosaic(gProgress[mID], gCancelComputation[mID]); t1 = now_ms(); time_c = t1 - t0; LOGV("CreateMosaic: %g ms",time_c); // Get back the result resultYVU = mosaic[mID]->getMosaic(mosaicWidth, mosaicHeight); + + return ret; } void YUV420toYVU24(ImageType yvu24, ImageType yuv420sp, int width, int height) @@ -532,23 +535,33 @@ JNIEXPORT void JNICALL Java_com_android_camera_panorama_Mosaic_reset( gProgress[LR] = 0.0; gProgress[HR] = 0.0; + gCancelComputation[LR] = false; + gCancelComputation[HR] = false; + Init(LR,MAX_FRAMES_LR); } JNIEXPORT jint JNICALL Java_com_android_camera_panorama_Mosaic_reportProgress( - JNIEnv* env, jobject thiz, jboolean hires) + JNIEnv* env, jobject thiz, jboolean hires, jboolean cancel_computation) { if(bool(hires)) + gCancelComputation[HR] = cancel_computation; + else + gCancelComputation[LR] = cancel_computation; + + if(bool(hires)) return (jint) gProgress[HR]; else return (jint) gProgress[LR]; } -JNIEXPORT void JNICALL Java_com_android_camera_panorama_Mosaic_createMosaic( +JNIEXPORT jint JNICALL Java_com_android_camera_panorama_Mosaic_createMosaic( JNIEnv* env, jobject thiz, jboolean value) { high_res = bool(value); + int ret; + if(high_res) { double t0, t1, time_c; @@ -560,28 +573,41 @@ JNIEXPORT void JNICALL Java_com_android_camera_panorama_Mosaic_createMosaic( for(int k = 0; k < frame_number_HR; k++) { + if (gCancelComputation[HR]) + break; AddFrame(HR, k, NULL); gProgress[HR] += TIME_PERCENT_ALIGN/frame_number_HR; } - gProgress[HR] = TIME_PERCENT_ALIGN; + if (gCancelComputation[HR]) + { + ret = Mosaic::MOSAIC_RET_CANCELLED; + } + else + { + gProgress[HR] = TIME_PERCENT_ALIGN; - t1 = now_ms(); - time_c = t1 - t0; - LOGV("AlignAll [HR]: %g ms",time_c); + t1 = now_ms(); + time_c = t1 - t0; + LOGV("AlignAll [HR]: %g ms",time_c); - Finalize(HR); + ret = Finalize(HR); - gProgress[HR] = 100.0; + gProgress[HR] = 100.0; + } high_res = false; } else { gProgress[LR] = TIME_PERCENT_ALIGN; - Finalize(LR); + + ret = Finalize(LR); + gProgress[LR] = 100.0; } + + return (jint) ret; } JNIEXPORT jintArray JNICALL Java_com_android_camera_panorama_Mosaic_getFinalMosaic( diff --git a/src/com/android/camera/panorama/Mosaic.java b/src/com/android/camera/panorama/Mosaic.java index ef9d367..b586aad 100644 --- a/src/com/android/camera/panorama/Mosaic.java +++ b/src/com/android/camera/panorama/Mosaic.java @@ -67,6 +67,13 @@ public class Mosaic { */ public static final int BLENDTYPE_HORIZONTAL =3; + /** + * Return flags returned by createMosaic() are one of the following. + */ + public static final int MOSAIC_RET_OK = 1; + public static final int MOSAIC_RET_ERROR = -1; + public static final int MOSAIC_RET_CANCELLED = -2; + static { System.loadLibrary("jni_mosaic"); } @@ -129,8 +136,10 @@ public class Mosaic { * which is based on the original images set in setSourceImage(). * False means generating a low-resolution version - * which is based on 1/4 downscaled images from the original images. + * @return Returns a status code suggesting if the mosaic building was + * successful, in error, or was cancelled by the user. */ - public native void createMosaic(boolean value); + public native int createMosaic(boolean value); /** * Get the data for the created mosaic. @@ -161,8 +170,10 @@ public class Mosaic { * Get the progress status of the mosaic computation process. * @param hires Boolean flag to select whether to report progress of the * low-res or high-res mosaicer. + * @param cancelComputation Boolean flag to allow cancelling the + * mosaic computation when needed from the GUI end. * @return Returns a number from 0-100 where 50 denotes that the mosaic * computation is 50% done. */ - public native int reportProgress(boolean hires); + public native int reportProgress(boolean hires, boolean cancelComputation); } diff --git a/src/com/android/camera/panorama/MosaicFrameProcessor.java b/src/com/android/camera/panorama/MosaicFrameProcessor.java index c67508f..dde4a22 100644 --- a/src/com/android/camera/panorama/MosaicFrameProcessor.java +++ b/src/com/android/camera/panorama/MosaicFrameProcessor.java @@ -78,8 +78,8 @@ public class MosaicFrameProcessor { mProgressListener = listener; } - public int reportProgress(boolean hires) { - return mMosaicer.reportProgress(hires); + public int reportProgress(boolean hires, boolean cancel) { + return mMosaicer.reportProgress(hires, cancel); } public void initialize() { @@ -126,8 +126,8 @@ public class MosaicFrameProcessor { mMosaicer.reset(); } - public void createMosaic(boolean highRes) { - mMosaicer.createMosaic(highRes); + public int createMosaic(boolean highRes) { + return mMosaicer.createMosaic(highRes); } public byte[] getFinalMosaicNV21() { diff --git a/src/com/android/camera/panorama/PanoramaActivity.java b/src/com/android/camera/panorama/PanoramaActivity.java index c2cb837..0aefb07 100644 --- a/src/com/android/camera/panorama/PanoramaActivity.java +++ b/src/com/android/camera/panorama/PanoramaActivity.java @@ -53,6 +53,8 @@ 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.net.Uri; import android.os.Bundle; import android.os.Handler; @@ -62,6 +64,7 @@ import android.view.Gravity; import android.view.OrientationEventListener; import android.view.View; import android.view.WindowManager; +import android.widget.Button; import android.widget.ImageView; import android.widget.RelativeLayout; import android.widget.TextView; @@ -84,6 +87,7 @@ public class PanoramaActivity extends Activity implements private static final int MSG_RESET_TO_PREVIEW_WITH_THUMBNAIL = 2; private static final int MSG_GENERATE_FINAL_MOSAIC_ERROR = 3; private static final int MSG_DISMISS_ALERT_DIALOG_AND_RESET_TO_PREVIEW = 4; + private static final int MSG_GENERATE_FINAL_MOSAIC_CANCELLED = 5; private static final String TAG = "PanoramaActivity"; private static final int PREVIEW_STOPPED = 0; @@ -155,6 +159,8 @@ public class PanoramaActivity extends Activity implements private Handler mMainHandler; private SurfaceTexture mSurfaceTexture; private boolean mThreadRunning; + private boolean mCancelComputation; + private int mMosaicComputationStatus; private float[] mTransformMatrix; private float mHorizontalViewAngle; @@ -247,6 +253,9 @@ public class PanoramaActivity extends Activity implements mAlertDialog = null; resetToPreview(); break; + case MSG_GENERATE_FINAL_MOSAIC_CANCELLED: + onBackgroundThreadFinished(); + resetToPreview(); } clearMosaicFrameProcessorIfNeeded(); } @@ -469,12 +478,15 @@ public class PanoramaActivity extends Activity implements @Override public void run() { MosaicJpeg jpeg = generateFinalMosaic(false); - Bitmap bitmap = null; - if (jpeg != null) { - bitmap = BitmapFactory.decodeByteArray(jpeg.data, 0, jpeg.data.length); + + if (mMosaicComputationStatus == Mosaic.MOSAIC_RET_OK) { + Bitmap bitmap = null; + if (jpeg != null) { + bitmap = BitmapFactory.decodeByteArray(jpeg.data, 0, jpeg.data.length); + } + mMainHandler.sendMessage(mMainHandler.obtainMessage( + MSG_LOW_RES_FINAL_MOSAIC_READY, bitmap)); } - mMainHandler.sendMessage(mMainHandler.obtainMessage( - MSG_LOW_RES_FINAL_MOSAIC_READY, bitmap)); } }); reportProgress(false); @@ -561,7 +573,8 @@ public class PanoramaActivity extends Activity implements @Override public void run() { while (mThreadRunning) { - final int progress = mMosaicFrameProcessor.reportProgress(highRes); + final int progress = mMosaicFrameProcessor.reportProgress( + highRes, mCancelComputation); try { Thread.sleep(50); @@ -591,20 +604,27 @@ public class PanoramaActivity extends Activity implements @Override public void run() { MosaicJpeg jpeg = generateFinalMosaic(true); - if (jpeg == null) { - mMainHandler.sendEmptyMessage(MSG_GENERATE_FINAL_MOSAIC_ERROR); + + if (mMosaicComputationStatus == Mosaic.MOSAIC_RET_CANCELLED) { + mMainHandler.sendEmptyMessage(MSG_GENERATE_FINAL_MOSAIC_CANCELLED); } else { - int orientation = Exif.getOrientation(jpeg.data); - Uri uri = savePanorama(jpeg.data, orientation); - if (uri != null) { - // Create a thumbnail whose width is equal or bigger than the entire screen. - int ratio = (int) Math.ceil((double) jpeg.width / mPanoLayout.getWidth()); - int inSampleSize = Integer.highestOneBit(ratio); - mThumbnail = Thumbnail.createThumbnail( - jpeg.data, orientation, inSampleSize, uri); + if (jpeg == null) { + mMainHandler.sendEmptyMessage(MSG_GENERATE_FINAL_MOSAIC_ERROR); + } else { + int orientation = Exif.getOrientation(jpeg.data); + Uri uri = savePanorama(jpeg.data, orientation); + if (uri != null) { + // Create a thumbnail whose width is equal or bigger + // than the entire screen. + int ratio = (int) Math.ceil((double) jpeg.width / + mPanoLayout.getWidth()); + int inSampleSize = Integer.highestOneBit(ratio); + mThumbnail = Thumbnail.createThumbnail( + jpeg.data, orientation, inSampleSize, uri); + } + mMainHandler.sendMessage( + mMainHandler.obtainMessage(MSG_RESET_TO_PREVIEW_WITH_THUMBNAIL)); } - mMainHandler.sendMessage( - mMainHandler.obtainMessage(MSG_RESET_TO_PREVIEW_WITH_THUMBNAIL)); } } }); @@ -622,7 +642,17 @@ public class PanoramaActivity extends Activity implements mProgressDialog.setMax(100); mProgressDialog.setMessage(str); mProgressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL); - mProgressDialog.setCancelable(false); // Don't allow back key to dismiss this dialog. + // TODO: update the UI according to specs. +// mProgressDialog.setCancelable(false); // Don't allow back key to dismiss this dialog. + mProgressDialog.setCancelable(true); + + mProgressDialog.setButton(DialogInterface.BUTTON_NEGATIVE, "Cancel", + new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, + int whichButton) { + mCancelComputation = true; + } + }); mProgressDialog.show(); } else { mPanoramaPrepareDialogFadeIn.start(); @@ -669,6 +699,7 @@ public class PanoramaActivity extends Activity implements private void resetToPreview() { mCaptureState = CAPTURE_STATE_VIEWFINDER; + mCancelComputation = false; mReviewLayout.setVisibility(View.GONE); mShutterButton.setBackgroundResource(R.drawable.btn_shutter_pan); @@ -804,7 +835,12 @@ public class PanoramaActivity extends Activity implements }; public MosaicJpeg generateFinalMosaic(boolean highRes) { - mMosaicFrameProcessor.createMosaic(highRes); + int ret = mMosaicFrameProcessor.createMosaic(highRes); + + mMosaicComputationStatus = ret; + + if (ret == Mosaic.MOSAIC_RET_CANCELLED) + return null; byte[] imageData = mMosaicFrameProcessor.getFinalMosaicNV21(); if (imageData == null) { |