diff options
-rw-r--r-- | assets/dependency.json | 8 | ||||
-rw-r--r-- | src/com/android/camera/CaptureModule.java | 70 | ||||
-rw-r--r-- | src/com/android/camera/CaptureUI.java | 1 | ||||
-rw-r--r-- | src/com/android/camera/SettingsActivity.java | 11 | ||||
-rw-r--r-- | src/com/android/camera/imageprocessor/PostProcessor.java | 274 | ||||
-rw-r--r-- | src/com/android/camera/imageprocessor/ZSLQueue.java | 74 | ||||
-rw-r--r-- | src/com/android/camera/util/CameraUtil.java | 28 |
7 files changed, 322 insertions, 144 deletions
diff --git a/assets/dependency.json b/assets/dependency.json index e415a1cec..b8c396895 100644 --- a/assets/dependency.json +++ b/assets/dependency.json @@ -70,6 +70,12 @@ "0":{}, "default": {"pref_camera2_facedetection_key":"on", - "pref_camera2_video_quality_key":"720x480"} + "pref_camera2_video_quality_key":"720x480", + "pref_camera2_longshot_key":"off"} + }, + "pref_camera2_selfiemirror_key": + { + "on":{"pref_camera2_longshot_key":"off"}, + "off":{} } } diff --git a/src/com/android/camera/CaptureModule.java b/src/com/android/camera/CaptureModule.java index acd9de91a..7e7b60414 100644 --- a/src/com/android/camera/CaptureModule.java +++ b/src/com/android/camera/CaptureModule.java @@ -178,7 +178,7 @@ public class CaptureModule implements CameraModule, PhotoController, CaptureRequest.Key<Integer> BayerMonoLinkSessionIdKey = new CaptureRequest.Key<>("org.codeaurora.qcamera3.dualcam_link_meta_data" + ".related_camera_id", Integer.class); - CaptureRequest.Key<Integer> CdsModeKey = + public static CaptureRequest.Key<Integer> CdsModeKey = new CaptureRequest.Key<>("org.codeaurora.qcamera3.CDS.cds_mode", Integer.class); public static CaptureRequest.Key<Byte> JpegCropEnableKey = new CaptureRequest.Key<>("org.codeaurora.qcamera3.jpeg_encode_crop.enable", @@ -729,6 +729,10 @@ public class CaptureModule implements CameraModule, PhotoController, return CameraProfile.getJpegEncodingQualityParameter(value); } + public LocationManager getLocationManager() { + return mLocationManager; + } + private void initializeFirstTime() { if (mFirstTimeInitialized || mPaused) { return; @@ -849,7 +853,7 @@ public class CaptureModule implements CameraModule, PhotoController, } if (isClearSightOn()) { ClearSightImageProcessor.getInstance().onCaptureSessionConfigured(id == BAYER_ID, cameraCaptureSession); - } else if (mChosenImageFormat == ImageFormat.YUV_420_888 && id == getMainCameraId()) { + } else if (mChosenImageFormat == ImageFormat.PRIVATE && id == getMainCameraId()) { mPostProcessor.onSessionConfigured(mCameraDevice[id], mCaptureSession[id]); } } catch (CameraAccessException e) { @@ -903,7 +907,7 @@ public class CaptureModule implements CameraModule, PhotoController, list.add(surs); } list.add(mImageReader[id].getSurface()); - if(mChosenImageFormat == ImageFormat.YUV_420_888) { + if(mChosenImageFormat == ImageFormat.YUV_420_888 || mChosenImageFormat == ImageFormat.PRIVATE) { if (mPostProcessor.isZSLEnabled()) { mPreviewRequestBuilder[id].addTarget(mImageReader[id].getSurface()); list.add(mPostProcessor.getZSLReprocessImageReader().getSurface()); @@ -1053,13 +1057,17 @@ public class CaptureModule implements CameraModule, PhotoController, private boolean takeZSLPicture(int cameraId) { if(mPostProcessor.isZSLEnabled() && mPostProcessor.takeZSLPicture()) { - checkAndPlayShutterSound(cameraId); + checkAndPlayShutterSound(getMainCameraId()); mUI.enableShutter(true); return true; } return false; } + public boolean isLongShotActive() { + return mLongshotActive; + } + /** * Lock the focus as the first step for a still image capture. */ @@ -1297,7 +1305,7 @@ public class CaptureModule implements CameraModule, PhotoController, mMpoSaveHandler.obtainMessage(MpoSaveHandler.MSG_CONFIGURE, Long.valueOf(mCaptureStartTime)).sendToTarget(); } - if(mChosenImageFormat == ImageFormat.YUV_420_888) { // Case of ZSL, FrameFilter, SelfieMirror + if(mChosenImageFormat == ImageFormat.YUV_420_888 || mChosenImageFormat == ImageFormat.PRIVATE) { // Case of ZSL, FrameFilter, SelfieMirror mPostProcessor.onStartCapturing(); mCaptureSession[id].capture(captureBuilder.build(), mPostProcessor.getCaptureCallback(), mCaptureCallbackHandler); } else { @@ -1419,19 +1427,20 @@ public class CaptureModule implements CameraModule, PhotoController, ClearSightImageProcessor.getInstance().setCallback(this); } } else { - if (imageFormat == ImageFormat.YUV_420_888 && i == getMainCameraId()) { + if ((imageFormat == ImageFormat.YUV_420_888 || imageFormat == ImageFormat.PRIVATE) + && i == getMainCameraId()) { if(mPostProcessor.isZSLEnabled()) { mImageReader[i] = ImageReader.newInstance(mSupportedMaxPictureSize.getWidth(), - mSupportedMaxPictureSize.getHeight(), imageFormat, PostProcessor.MAX_REQUIRED_IMAGE_NUM); + mSupportedMaxPictureSize.getHeight(), imageFormat, mPostProcessor.getMaxRequiredImageNum()); } else { mImageReader[i] = ImageReader.newInstance(mPictureSize.getWidth(), - mPictureSize.getHeight(), imageFormat, PostProcessor.MAX_REQUIRED_IMAGE_NUM); + mPictureSize.getHeight(), imageFormat, mPostProcessor.getMaxRequiredImageNum()); } mImageReader[i].setOnImageAvailableListener(mPostProcessor.getImageHandler(), mImageAvailableHandler); mPostProcessor.onImageReaderReady(mImageReader[i], mSupportedMaxPictureSize, mPictureSize); } else { mImageReader[i] = ImageReader.newInstance(mPictureSize.getWidth(), - mPictureSize.getHeight(), imageFormat, PostProcessor.MAX_REQUIRED_IMAGE_NUM); + mPictureSize.getHeight(), imageFormat, PersistUtil.getLongshotShotLimit()); mImageReader[i].setOnImageAvailableListener(new ImageAvailableListener(i) { @Override @@ -1483,7 +1492,7 @@ public class CaptureModule implements CameraModule, PhotoController, mVideoSnapshotImageReader.close(); } mVideoSnapshotImageReader = ImageReader.newInstance(mVideoSnapshotSize.getWidth(), - mVideoSnapshotSize.getHeight(), ImageFormat.JPEG, mPostProcessor.MAX_REQUIRED_IMAGE_NUM); + mVideoSnapshotSize.getHeight(), ImageFormat.JPEG, 2); mVideoSnapshotImageReader.setOnImageAvailableListener( new ImageReader.OnImageAvailableListener() { @Override @@ -1959,13 +1968,18 @@ public class CaptureModule implements CameraModule, PhotoController, private void openProcessors() { String scene = mSettingsManager.getValue(SettingsManager.KEY_SCENE_MODE); - boolean isLongShotOn = false; boolean isFlashOn = false; boolean isTrackingFocusOn = false; + boolean isMakeupOn = false; + boolean isSelfieMirrorOn = false; if(mPostProcessor != null) { - String longshot = mSettingsManager.getValue(SettingsManager.KEY_LONGSHOT); - if(longshot != null && longshot.equalsIgnoreCase("on")) { - isLongShotOn = true; + String selfieMirror = mSettingsManager.getValue(SettingsManager.KEY_SELFIEMIRROR); + if(selfieMirror != null && selfieMirror.equalsIgnoreCase("on")) { + isSelfieMirrorOn = true; + } + String makeup = mSettingsManager.getValue(SettingsManager.KEY_MAKEUP); + if(makeup != null && !makeup.equals("0")) { + isMakeupOn = true; } String flashMode = mSettingsManager.getValue(SettingsManager.KEY_FLASH_MODE); if(flashMode != null && flashMode.equalsIgnoreCase("on")) { @@ -1978,17 +1992,18 @@ public class CaptureModule implements CameraModule, PhotoController, if (scene != null) { int mode = Integer.parseInt(scene); Log.d(TAG, "Chosen postproc filter id : " + getPostProcFilterId(mode)); - mPostProcessor.onOpen(getPostProcFilterId(mode), isLongShotOn, isFlashOn, isTrackingFocusOn); + mPostProcessor.onOpen(getPostProcFilterId(mode), isFlashOn, isTrackingFocusOn, isMakeupOn, isSelfieMirrorOn); } else { - mPostProcessor.onOpen(PostProcessor.FILTER_NONE, isLongShotOn, isFlashOn, isTrackingFocusOn); + mPostProcessor.onOpen(PostProcessor.FILTER_NONE, isFlashOn, isTrackingFocusOn, isMakeupOn, isSelfieMirrorOn); } } if(mFrameProcessor != null) { mFrameProcessor.onOpen(getFrameProcFilterId(), mPreviewSize); } - if(!isLongShotOn && - (mPostProcessor.isFilterOn() || getFrameFilters().size() != 0 || mPostProcessor.isZSLEnabled() || mPostProcessor.isSelfieMirrorOn())) { + if(mPostProcessor.isZSLEnabled()) { + mChosenImageFormat = ImageFormat.PRIVATE; + } else if(mPostProcessor.isFilterOn() || getFrameFilters().size() != 0 || mPostProcessor.isSelfieMirrorOn()) { mChosenImageFormat = ImageFormat.YUV_420_888; } else { mChosenImageFormat = ImageFormat.JPEG; @@ -2400,6 +2415,8 @@ public class CaptureModule implements CameraModule, PhotoController, public void onShutterButtonFocus(boolean pressed) { if (!pressed && mLongshotActive) { Log.d(TAG, "Longshot button up"); + mLongshotActive = false; + mPostProcessor.stopLongShot(); } } @@ -2416,6 +2433,10 @@ public class CaptureModule implements CameraModule, PhotoController, mPictureThumbSize = getOptimalPreviewSize(mPictureSize, thumbSizes, 0, 0); // get largest thumb size } + public Size getThumbSize() { + return mPictureThumbSize; + } + public boolean isRecordingVideo() { return mIsRecordingVideo; } @@ -2993,12 +3014,19 @@ public class CaptureModule implements CameraModule, PhotoController, } + public boolean isLongShotSettingEnabled() { + String longshot = mSettingsManager.getValue(SettingsManager.KEY_LONGSHOT); + if(longshot.equals("on")) { + return true; + } + return false; + } + @Override public void onShutterButtonLongClick() { if (isBackCamera() && getCameraMode() == DUAL_MODE) return; - String longshot = mSettingsManager.getValue(SettingsManager.KEY_LONGSHOT); - if (longshot.equals("on")) { + if (isLongShotSettingEnabled()) { //Cancel the previous countdown when long press shutter button for longshot. if (mUI.isCountingDown()) { mUI.cancelCountDown(); @@ -3313,7 +3341,7 @@ public class CaptureModule implements CameraModule, PhotoController, } } - private void checkAndPlayShutterSound(int id) { + public void checkAndPlayShutterSound(int id) { if (id == getMainCameraId()) { String value = mSettingsManager.getValue(SettingsManager.KEY_SHUTTER_SOUND); if (value != null && value.equals("on") && mSound != null) { diff --git a/src/com/android/camera/CaptureUI.java b/src/com/android/camera/CaptureUI.java index 6c4254cb6..b980bf7ef 100644 --- a/src/com/android/camera/CaptureUI.java +++ b/src/com/android/camera/CaptureUI.java @@ -392,6 +392,7 @@ public class CaptureUI implements FocusOverlayManager.FocusUI, mMakeupSeekBarLayout.setVisibility(View.VISIBLE); } else { mMakeupButton.setImageResource(R.drawable.beautify); + mMakeupSeekBarLayout.setVisibility(View.GONE); } } }); diff --git a/src/com/android/camera/SettingsActivity.java b/src/com/android/camera/SettingsActivity.java index 8482750ec..86d74b079 100644 --- a/src/com/android/camera/SettingsActivity.java +++ b/src/com/android/camera/SettingsActivity.java @@ -194,12 +194,13 @@ public class SettingsActivity extends PreferenceActivity { } private void updatePreferenceButton(String key) { - ListPreference pref = (ListPreference) findPreference(key); - if (pref != null) { - if (pref.getEntryValues().length == 1) { - pref.setEnabled(false); + Preference pref = findPreference(key); + if (pref != null && pref instanceof ListPreference) { + ListPreference pref2 = (ListPreference) pref; + if (pref2.getEntryValues().length == 1) { + pref2.setEnabled(false); } else { - pref.setEnabled(true); + pref2.setEnabled(true); } } } diff --git a/src/com/android/camera/imageprocessor/PostProcessor.java b/src/com/android/camera/imageprocessor/PostProcessor.java index 82467acaa..8e6caa953 100644 --- a/src/com/android/camera/imageprocessor/PostProcessor.java +++ b/src/com/android/camera/imageprocessor/PostProcessor.java @@ -43,6 +43,7 @@ import android.hardware.camera2.CaptureFailure; import android.hardware.camera2.CaptureRequest; import android.hardware.camera2.CaptureResult; import android.hardware.camera2.TotalCaptureResult; +import android.location.Location; import android.media.Image; import android.media.ImageReader; import android.media.ImageWriter; @@ -81,6 +82,8 @@ import java.util.concurrent.Semaphore; import com.android.camera.imageprocessor.filter.ImageFilter; import com.android.camera.util.CameraUtil; +import com.android.camera.util.PersistUtil; + import android.util.Size; public class PostProcessor{ @@ -99,7 +102,7 @@ public class PostProcessor{ public static final int FILTER_MAX = 8; //BestPicture requires 10 which is the biggest among filters - public static final int MAX_REQUIRED_IMAGE_NUM = 11; + private static final int MAX_REQUIRED_IMAGE_NUM = 11; private int mCurrentNumImage = 0; private ImageFilter mFilter; private int mFilterIndex; @@ -117,10 +120,10 @@ public class PostProcessor{ private int mOrientation = 0; private ImageWriter mImageWriter; - //This is for the debug feature. private static boolean DEBUG_FILTER = false; - private static boolean DEBUG_ZSL = true; + private static boolean DEBUG_ZSL = false; private ImageFilter.ResultImage mDebugResultImage; + private ZSLQueue mZSLQueue; private CameraDevice mCameraDevice; private CameraCaptureSession mCaptureSession; @@ -129,10 +132,20 @@ public class PostProcessor{ private boolean mUseZSL = true; private Handler mZSLHandler; private HandlerThread mZSLHandlerThread; + private Handler mSavingHander; + private HandlerThread mSavingHandlerThread; private ImageHandlerTask mImageHandlerTask; private LinkedList<TotalCaptureResult> mTotalCaptureResultList = new LinkedList<TotalCaptureResult>(); private TotalCaptureResult mZSLFallOffResult = null; - private boolean mIsZSLFallOffForFlash = false; + private boolean mIsZSLFallOff = false; + private TotalCaptureResult mLatestResultForLongShot = null; + private LinkedList<Image> mFallOffImages = new LinkedList<Image>(); + private int mPendingContinuousRequestCount = 0; + public int mMaxRequiredImageNum; + + public int getMaxRequiredImageNum() { + return mMaxRequiredImageNum; + } public boolean isZSLEnabled() { return mUseZSL; @@ -169,6 +182,42 @@ public class PostProcessor{ } } + private void clearFallOffImage() { + for(Image im: mFallOffImages ) { + try { + im.close(); + } catch(Exception e) { + } + } + mFallOffImages.clear(); + } + + private Image findFallOffImage(long timestamp) { + Image foundImage = null; + for(Image im: mFallOffImages ) { + if(im.getTimestamp() == timestamp) { + foundImage = im; + break; + } + } + if(foundImage != null) { + mFallOffImages.remove(foundImage); + } + return foundImage; + } + + private void addFallOffImage(Image image) { + mFallOffImages.add(image); + if(mFallOffImages.size() >= MAX_REQUIRED_IMAGE_NUM - 1) { + Image im = mFallOffImages.getFirst(); + try { + im.close(); + } catch(Exception e) { + } + mFallOffImages.removeFirst(); + } + } + class ImageHandlerTask implements Runnable, ImageReader.OnImageAvailableListener { private ImageWrapper mImageWrapper = null; Semaphore mMutureLock = new Semaphore(1); @@ -177,15 +226,31 @@ public class PostProcessor{ public void onImageAvailable(ImageReader reader) { try { if(mUseZSL) { - if(mIsZSLFallOffForFlash && mZSLFallOffResult != null) { + if(mController.isLongShotActive() && mPendingContinuousRequestCount > 0) { + Image image = reader.acquireNextImage(); + ZSLQueue.ImageItem item = new ZSLQueue.ImageItem(); + item.setImage(image); + if(onContinuousZSLImage(item, true)) { + image.close(); + } + return; + } + if(mIsZSLFallOff) { Image image = reader.acquireNextImage(); - if((mZSLFallOffResult.get(CaptureResult.SENSOR_TIMESTAMP)).longValue() <= image.getTimestamp()) { - Log.d(TAG,"ZSL fall off for flash image"); - mIsZSLFallOffForFlash = false; - reprocessImage(image, mZSLFallOffResult); + if(mZSLFallOffResult == null) { + addFallOffImage(image); + return; + } + addFallOffImage(image); + Image foundImage = findFallOffImage(mZSLFallOffResult.get(CaptureResult.SENSOR_TIMESTAMP).longValue()); + if(foundImage != null) { + Log.d(TAG,"ZSL fall off image is found"); + reprocessImage(foundImage, mZSLFallOffResult); + mIsZSLFallOff = false; + clearFallOffImage(); mZSLFallOffResult = null; } else { - image.close(); + clearFallOffImage(); } return; } @@ -217,8 +282,9 @@ public class PostProcessor{ } } catch (IllegalStateException e) { Log.e(TAG, "Max images has been already acquired. "); - mIsZSLFallOffForFlash = false; + mIsZSLFallOff = false; mZSLFallOffResult = null; + clearFallOffImage(); } } @@ -242,6 +308,7 @@ public class PostProcessor{ if(mUseZSL && mZSLQueue != null) { mZSLQueue.add(metadata); } + mLatestResultForLongShot = metadata; } CameraCaptureSession.CaptureCallback mCaptureCallback = new CameraCaptureSession.CaptureCallback() { @@ -253,7 +320,7 @@ public class PostProcessor{ if(mTotalCaptureResultList.size() <= PostProcessor.MAX_REQUIRED_IMAGE_NUM) { mTotalCaptureResultList.add(result); } - if(mIsZSLFallOffForFlash) { + if(mIsZSLFallOff) { mZSLFallOffResult = result; } else { onMetaAvailable(result); @@ -283,14 +350,14 @@ public class PostProcessor{ mCameraDevice = cameraDevice; mCaptureSession = captureSession; if(mUseZSL) { - mImageWriter = ImageWriter.newInstance(captureSession.getInputSurface(), 2); + mImageWriter = ImageWriter.newInstance(captureSession.getInputSurface(), mMaxRequiredImageNum); } } public void onImageReaderReady(ImageReader imageReader, Size maxSize, Size pictureSize) { mImageReader = imageReader; if(mUseZSL) { - mZSLReprocessImageReader = ImageReader.newInstance(pictureSize.getWidth(), pictureSize.getHeight(), ImageFormat.YUV_420_888, 2); + mZSLReprocessImageReader = ImageReader.newInstance(pictureSize.getWidth(), pictureSize.getHeight(), ImageFormat.JPEG, mMaxRequiredImageNum); mZSLReprocessImageReader.setOnImageAvailableListener(processedImageAvailableListener, mHandler); } } @@ -300,53 +367,131 @@ public class PostProcessor{ if(mController.getPreviewCaptureResult() == null || mController.getPreviewCaptureResult().get(CaptureResult.CONTROL_AE_STATE) == CameraMetadata.CONTROL_AE_STATE_FLASH_REQUIRED) { if(DEBUG_ZSL) Log.d(TAG, "Flash required image"); - mIsZSLFallOffForFlash = true; imageItem = null; } if (mController.isSelfieFlash()) { imageItem = null; } + if (mController.isLongShotActive()) { + imageItem = null; + } if (imageItem != null) { if(DEBUG_ZSL) Log.d(TAG,"Got the item from the queue"); reprocessImage(imageItem.getImage(), imageItem.getMetadata()); return true; } else { if(DEBUG_ZSL) Log.d(TAG, "No good item in queue, register the request for the future"); - if(!mIsZSLFallOffForFlash) { - mZSLQueue.addPictureRequest(); + if(mController.isLongShotActive()) { + if(DEBUG_ZSL) Log.d(TAG, "Long shot active in ZSL"); + mPendingContinuousRequestCount = PersistUtil.getLongshotShotLimit(); + return true; + } else { + mIsZSLFallOff = true; } return false; } } - public void onMatchingZSLPictureAvailable(ZSLQueue.ImageItem imageItem) { - reprocessImage(imageItem.getImage(), imageItem.getMetadata()); + public boolean onContinuousZSLImage(ZSLQueue.ImageItem imageItem, boolean isLongShotRequest) { + if(isLongShotRequest) { + if(mLatestResultForLongShot != null) { + reprocessImage(imageItem.getImage(), mLatestResultForLongShot); + mPendingContinuousRequestCount--; + return true; + } + } else { + reprocessImage(imageItem.getImage(), imageItem.getMetadata()); + return true; + } + + return false; + } + + public void stopLongShot() { + mPendingContinuousRequestCount = 0; } private void reprocessImage(Image image, TotalCaptureResult metadata) { - if(mCameraDevice == null || mCaptureSession == null || mImageReader == null) { - Log.e(TAG, "Reprocess request is called even before taking picture"); - new Throwable().printStackTrace(); - return; + if(mController.isLongShotActive()) { + mController.checkAndPlayShutterSound(mController.getMainCameraId()); } - Log.d(TAG, "reprocess Image request"); - CaptureRequest.Builder builder = null; - try { - builder = mCameraDevice.createReprocessCaptureRequest(metadata); - builder.addTarget(mZSLReprocessImageReader.getSurface()); - builder.set(CaptureRequest.COLOR_CORRECTION_ABERRATION_MODE, - CaptureRequest.COLOR_CORRECTION_ABERRATION_MODE_HIGH_QUALITY); - builder.set(CaptureRequest.EDGE_MODE, - CaptureRequest.EDGE_MODE_HIGH_QUALITY); - builder.set(CaptureRequest.NOISE_REDUCTION_MODE, - CaptureRequest.NOISE_REDUCTION_MODE_HIGH_QUALITY); + synchronized (lock) { + if(mCameraDevice == null || mCaptureSession == null || mImageReader == null) { + Log.e(TAG, "Reprocess request is called even before taking picture"); + image.close(); + return; + } + if (mZSLReprocessImageReader == null) { + image.close(); + return; + } + if (DEBUG_ZSL) Log.d(TAG, "reprocess Image request " + image.getTimestamp()); + CaptureRequest.Builder builder = null; try { - mImageWriter.queueInputImage(image); - } catch(IllegalStateException e) { - Log.e(TAG, "Queueing more than it can have"); + builder = mCameraDevice.createReprocessCaptureRequest(metadata); + builder.set(CaptureRequest.JPEG_ORIENTATION, + CameraUtil.getJpegRotation(mController.getMainCameraId(), mController.getDisplayOrientation())); + builder.set(CaptureRequest.JPEG_THUMBNAIL_SIZE, mController.getThumbSize()); + builder.set(CaptureRequest.JPEG_THUMBNAIL_QUALITY, (byte)80); + builder.set(CaptureRequest.COLOR_CORRECTION_ABERRATION_MODE, + CaptureRequest.COLOR_CORRECTION_ABERRATION_MODE_HIGH_QUALITY); + builder.set(CaptureRequest.EDGE_MODE, + CaptureRequest.EDGE_MODE_HIGH_QUALITY); + builder.set(CaptureRequest.NOISE_REDUCTION_MODE, + CaptureRequest.NOISE_REDUCTION_MODE_HIGH_QUALITY); + builder.set(CaptureModule.CdsModeKey, 2); // CDS 0-OFF, 1-ON, 2-AUTO + builder.set(CaptureModule.JpegCropEnableKey, (byte)1); + Rect cropRect = image.getCropRect(); + if(cropRect == null || + cropRect.isEmpty()) { + cropRect = new Rect(0, 0, image.getWidth(), image.getHeight()); + } + + int targetWidth = mZSLReprocessImageReader.getWidth(); + int targetHeight = mZSLReprocessImageReader.getHeight(); + float targetRatio = (float)targetWidth / (float)targetHeight; + cropRect = CameraUtil.getFinalCropRect(cropRect, targetRatio); + // has crop rect. apply to jpeg request + builder.set(CaptureModule.JpegCropRectKey, + new int[] {cropRect.left, cropRect.top, cropRect.width(), cropRect.height()}); + builder.set(CaptureModule.JpegRoiRectKey, + new int[] {0, 0, targetWidth, targetHeight}); + + Location location = mController.getLocationManager().getCurrentLocation(); + if(location != null) { + location = new Location(location); + Log.d(TAG, "sendReprocessRequest gps: " + location.toString()); + // workaround for Google bug. Need to convert timestamp from ms -> sec + location.setTime(location.getTime()/1000); + builder.set(CaptureRequest.JPEG_GPS_LOCATION, location); + } + + builder.addTarget(mZSLReprocessImageReader.getSurface()); + try { + mImageWriter.queueInputImage(image); + } catch (IllegalStateException e) { + Log.e(TAG, "Queueing more than it can have"); + } + mCaptureSession.capture(builder.build(), new CameraCaptureSession.CaptureCallback(){ + @Override + public void onCaptureCompleted(CameraCaptureSession session, + CaptureRequest request, + TotalCaptureResult result) { + } + + @Override + public void onCaptureFailed(CameraCaptureSession session, + CaptureRequest request, + CaptureFailure result) { + } + + @Override + public void onCaptureSequenceCompleted(CameraCaptureSession session, int + sequenceId, long frameNumber) { + } + }, mHandler); + } catch (CameraAccessException e) { } - mCaptureSession.capture(builder.build(), mCaptureCallback, mHandler); - } catch (CameraAccessException e) { } } @@ -428,10 +573,11 @@ public class PostProcessor{ return false; } - public void onOpen(int postFilterId, boolean isLongShotOn, boolean isFlashModeOn, boolean isTrackingFocusOn) { + public void onOpen(int postFilterId, boolean isFlashModeOn, boolean isTrackingFocusOn, boolean isMakeupOn, boolean isSelfieMirrorOn) { mImageHandlerTask = new ImageHandlerTask(); - if(setFilter(postFilterId) || isLongShotOn || isFlashModeOn || isTrackingFocusOn) { + if(setFilter(postFilterId) || isFlashModeOn || isTrackingFocusOn || isMakeupOn || isSelfieMirrorOn + || PersistUtil.getCameraZSLDisabled()) { mUseZSL = false; } else { mUseZSL = true; @@ -441,6 +587,11 @@ public class PostProcessor{ if(mUseZSL) { mZSLQueue = new ZSLQueue(mController); } + mMaxRequiredImageNum = MAX_REQUIRED_IMAGE_NUM; + if(mController.isLongShotSettingEnabled()) { + mMaxRequiredImageNum = Math.max(MAX_REQUIRED_IMAGE_NUM, PersistUtil.getLongshotShotLimit()+2); + } + mPendingContinuousRequestCount = 0; } public int getFilterIndex() { @@ -470,6 +621,7 @@ public class PostProcessor{ mCameraDevice = null; mCaptureSession = null; mImageReader = null; + mPendingContinuousRequestCount = 0; } private void startBackgroundThread() { @@ -481,6 +633,10 @@ public class PostProcessor{ mZSLHandlerThread.start(); mZSLHandler = new ProcessorHandler(mZSLHandlerThread.getLooper()); + mSavingHandlerThread = new HandlerThread("SavingHandlerThread"); + mSavingHandlerThread.start(); + mSavingHander = new ProcessorHandler(mSavingHandlerThread.getLooper()); + mWatchdog = new WatchdogThread(); mWatchdog.start(); } @@ -557,6 +713,15 @@ public class PostProcessor{ mZSLHandlerThread = null; mZSLHandler = null; } + if (mSavingHandlerThread != null) { + mSavingHandlerThread.quitSafely(); + try { + mSavingHandlerThread.join(); + } catch (InterruptedException e) { + } + mSavingHandlerThread = null; + mSavingHander = null; + } if(mWatchdog != null) { mWatchdog.kill(); mWatchdog = null; @@ -851,11 +1016,28 @@ public class PostProcessor{ ImageReader.OnImageAvailableListener processedImageAvailableListener = new ImageReader.OnImageAvailableListener() { @Override public void onImageAvailable(ImageReader reader) { - Log.d(TAG, "ZSL image Reprocess is done"); - Image image = reader.acquireNextImage(); - if(image != null) { - onImageToProcess(image); - } + final Image image = reader.acquireNextImage(); + if(DEBUG_ZSL) Log.d(TAG, "ZSL image Reprocess is done "+image.getTimestamp()); + mSavingHander.post(new Runnable() { + public void run() { + long captureStartTime = System.currentTimeMillis(); + mNamedImages.nameNewImage(captureStartTime); + PhotoModule.NamedImages.NamedEntity name = mNamedImages.getNextNameEntity(); + String title = (name == null) ? null : name.title; + long date = (name == null) ? -1 : name.date; + image.getPlanes()[0].getBuffer().rewind(); + int size = image.getPlanes()[0].getBuffer().remaining(); + byte[] bytes = new byte[size]; + image.getPlanes()[0].getBuffer().get(bytes, 0, size); + ExifInterface exif = Exif.getExif(bytes); + int orientation = Exif.getOrientation(exif); + mActivity.getMediaSaveService().addImage( + bytes, title, date, null, image.getCropRect().width(), image.getCropRect().height(), + orientation, null, mController.getMediaSavedListener(), mActivity.getContentResolver(), "jpeg"); + mController.updateThumbnailJpegData(bytes); + image.close(); + } + }); } }; diff --git a/src/com/android/camera/imageprocessor/ZSLQueue.java b/src/com/android/camera/imageprocessor/ZSLQueue.java index 792489cbc..f50858a35 100644 --- a/src/com/android/camera/imageprocessor/ZSLQueue.java +++ b/src/com/android/camera/imageprocessor/ZSLQueue.java @@ -36,7 +36,9 @@ import android.util.Log; import com.android.camera.CaptureModule; import android.os.SystemProperties; +import java.util.Iterator; import java.util.LinkedList; +import java.util.NoSuchElementException; public class ZSLQueue { private static final String CIRCULAR_BUFFER_SIZE_PERSIST = "persist.camera.zsl.buffer.size"; @@ -46,28 +48,10 @@ public class ZSLQueue { private int mImageHead; private int mMetaHead; private Object mLock = new Object(); - private LinkedList<PendingRequest> mPendingRequestList = new LinkedList<PendingRequest>(); private CaptureModule mModule; private static final boolean DEBUG = false; private static final boolean DEBUG_QUEUE = false; private static final String TAG = "ZSLQueue"; - private static final int REQUEST_LIFESPAN = 5; //This is in frame count. - - class PendingRequest { - private int mLifeTimeInFrame; - - public PendingRequest(){ - mLifeTimeInFrame = 0; - } - - public int getLifeTime() { - return mLifeTimeInFrame; - } - - public void incLifeTime() { - mLifeTimeInFrame++; - } - } public ZSLQueue(CaptureModule module) { mCircularBufferSize = SystemProperties.getInt(CIRCULAR_BUFFER_SIZE_PERSIST, CIRCULAR_BUFFER_SIZE_DEFAULT); @@ -75,7 +59,6 @@ public class ZSLQueue { mBuffer = new ImageItem[mCircularBufferSize]; mImageHead = 0; mMetaHead = 0; - mPendingRequestList.clear(); mModule = module; } } @@ -141,40 +124,6 @@ public class ZSLQueue { } if(DEBUG_QUEUE) Log.d(TAG, "imageIndex: " + lastIndex + " " + image.getTimestamp()); - - if(mPendingRequestList.size() != 0) { - if(lastIndex != -1) { - processPendingRequest(lastIndex); - } - for(int i=0; i < mPendingRequestList.size(); i++) { - mPendingRequestList.get(i).incLifeTime(); - } - } - } - - private void processPendingRequest(int index) { - ImageItem item; - synchronized (mLock) { - if(mBuffer == null) - return; - item = mBuffer[index]; - if (item != null && item.isValid() && checkImageRequirement(item.getMetadata())) { - if(DEBUG && (mBuffer[index].getMetadata().get(CaptureResult.SENSOR_TIMESTAMP)).longValue() != - mBuffer[index].getImage().getTimestamp()) { - Log.e(TAG,"Not matching image coming through"); - } - mBuffer[index] = null; - mPendingRequestList.removeFirst(); - for(PendingRequest request : mPendingRequestList) { - if(request.getLifeTime() >= REQUEST_LIFESPAN) { - mPendingRequestList.remove(request); - } - } - } else { - return; - } - } - mModule.getPostProcessor().onMatchingZSLPictureAvailable(item); } public void add(TotalCaptureResult metadata) { @@ -224,15 +173,6 @@ public class ZSLQueue { } if(DEBUG_QUEUE) Log.d(TAG, "Meta: " + lastIndex + " " + metadata.get(CaptureResult.SENSOR_TIMESTAMP)); - - if(mPendingRequestList.size() != 0) { - if(lastIndex != -1) { - processPendingRequest(lastIndex); - } - for(int i=0; i < mPendingRequestList.size(); i++) { - mPendingRequestList.get(i).incLifeTime(); - } - } } public ImageItem tryToGetMatchingItem() { @@ -252,13 +192,6 @@ public class ZSLQueue { return null; } - public void addPictureRequest() { - if(DEBUG) Log.d(TAG, "RequsetPendingCount: "+mPendingRequestList.size()); - synchronized (mLock) { - mPendingRequestList.addLast(new PendingRequest()); - } - } - public void onClose() { synchronized (mLock) { for (int i = 0; i < mBuffer.length; i++) { @@ -271,7 +204,6 @@ public class ZSLQueue { mBuffer = null; mImageHead = 0; mMetaHead = 0; - mPendingRequestList.clear(); } } @@ -304,7 +236,7 @@ public class ZSLQueue { return true; } - class ImageItem { + static class ImageItem { private Image mImage = null; private TotalCaptureResult mMetadata = null; diff --git a/src/com/android/camera/util/CameraUtil.java b/src/com/android/camera/util/CameraUtil.java index 1cdfd285a..1dc5e558b 100644 --- a/src/com/android/camera/util/CameraUtil.java +++ b/src/com/android/camera/util/CameraUtil.java @@ -842,6 +842,34 @@ public class CameraUtil { view.setVisibility(View.GONE); } + public static Rect getFinalCropRect(Rect rect, float targetRatio) { + Rect finalRect = new Rect(rect); + float rectRatio = (float) rect.width()/(float) rect.height(); + + // if ratios are different, adjust crop rect to fit ratio + // if ratios are same, no need to adjust crop + Log.d(TAG, "getFinalCropRect - rect: " + rect.toString()); + Log.d(TAG, "getFinalCropRect - ratios: " + rectRatio + ", " + targetRatio); + if(rectRatio > targetRatio) { + // ratio indicates need for horizontal crop + // add .5 to round up if necessary + int newWidth = (int)(((float)rect.height() * targetRatio) + .5f); + int newXoffset = (rect.width() - newWidth)/2 + rect.left; + finalRect.left = newXoffset; + finalRect.right = newXoffset + newWidth; + } else if(rectRatio < targetRatio) { + // ratio indicates need for vertical crop + // add .5 to round up if necessary + int newHeight = (int)(((float)rect.width() / targetRatio) + .5f); + int newYoffset = (rect.height() - newHeight)/2 + rect.top; + finalRect.top = newYoffset; + finalRect.bottom = newYoffset + newHeight; + } + + Log.d(TAG, "getFinalCropRect - final rect: " + finalRect.toString()); + return finalRect; + } + public static int getJpegRotation(int cameraId, int orientation) { // See android.hardware.Camera.Parameters.setRotation for // documentation. |