summaryrefslogtreecommitdiffstats
path: root/src/com/android/camera/imageprocessor
diff options
context:
space:
mode:
authorJack Yoo <jyoo@codeaurora.org>2016-05-10 14:11:19 -0700
committerJack Yoo <jyoo@codeaurora.org>2016-06-08 14:22:28 -0700
commit53cd3dd1a139d495fe25d06d439bd8fd0ea1d683 (patch)
tree9f5a48e869e2e7318cfd6e7da5e72a7438963b58 /src/com/android/camera/imageprocessor
parentcea7d5bfe6694009d7d4fa97e8bedaca8aff3e32 (diff)
downloadandroid_packages_apps_Snap-53cd3dd1a139d495fe25d06d439bd8fd0ea1d683.tar.gz
android_packages_apps_Snap-53cd3dd1a139d495fe25d06d439bd8fd0ea1d683.tar.bz2
android_packages_apps_Snap-53cd3dd1a139d495fe25d06d439bd8fd0ea1d683.zip
SnapdragonCamera: Sharpshooter post filter
Adding Sharpshooter post process filter Change-Id: I8f3c1962db437e7dfbe2973f806a3f9a26480eb7 CRs-Fixed: 1023183
Diffstat (limited to 'src/com/android/camera/imageprocessor')
-rw-r--r--src/com/android/camera/imageprocessor/FrameProcessor.java8
-rw-r--r--src/com/android/camera/imageprocessor/PostProcessor.java46
-rw-r--r--src/com/android/camera/imageprocessor/filter/OptizoomFilter.java2
-rw-r--r--src/com/android/camera/imageprocessor/filter/SharpshooterFilter.java172
4 files changed, 216 insertions, 12 deletions
diff --git a/src/com/android/camera/imageprocessor/FrameProcessor.java b/src/com/android/camera/imageprocessor/FrameProcessor.java
index 951479de9..6a2091158 100644
--- a/src/com/android/camera/imageprocessor/FrameProcessor.java
+++ b/src/com/android/camera/imageprocessor/FrameProcessor.java
@@ -128,7 +128,7 @@ public class FrameProcessor {
}
}
- private void createAllocation(int width, int height) {
+ private void createAllocation(int width, int height, int stridePad) {
Type.Builder yuvTypeBuilder = new Type.Builder(mRs, Element.YUV(mRs));
yuvTypeBuilder.setX(width);
yuvTypeBuilder.setY(height);
@@ -141,6 +141,8 @@ public class FrameProcessor {
mRsRotator.set_gOut(mProcessAllocation);
mRsRotator.set_width(width);
mRsRotator.set_height(height);
+ mRsRotator.set_pad(stridePad);
+ mRsRotator.set_gFlip(!mModule.isBackCamera());
mRsYuvToRGB.set_gIn(mProcessAllocation);
mRsYuvToRGB.set_width(height);
mRsYuvToRGB.set_height(width);
@@ -266,6 +268,7 @@ public class FrameProcessor {
int ySize;
int stride;
int height;
+ int width;
public ProcessingTask() {
}
@@ -288,6 +291,7 @@ public class FrameProcessor {
ByteBuffer bVU = image.getPlanes()[2].getBuffer();
if(yvuBytes == null) {
stride = image.getPlanes()[0].getRowStride();
+ width = mSize.getWidth();
height = mSize.getHeight();
ySize = stride * mSize.getHeight();
yvuBytes = new byte[ySize*3/2];
@@ -314,7 +318,7 @@ public class FrameProcessor {
return;
}
if(mInputAllocation == null) {
- createAllocation(stride, height);
+ createAllocation(stride, height, stride-width);
}
mInputAllocation.copyFrom(yvuBytes);
mRsRotator.forEach_rotate90andMerge(mInputAllocation);
diff --git a/src/com/android/camera/imageprocessor/PostProcessor.java b/src/com/android/camera/imageprocessor/PostProcessor.java
index a126e8817..f39845346 100644
--- a/src/com/android/camera/imageprocessor/PostProcessor.java
+++ b/src/com/android/camera/imageprocessor/PostProcessor.java
@@ -43,17 +43,24 @@ import android.widget.Toast;
import com.android.camera.CameraActivity;
import com.android.camera.CaptureModule;
+import com.android.camera.Exif;
import com.android.camera.MediaSaveService;
import com.android.camera.PhotoModule;
import com.android.camera.SettingsManager;
+import com.android.camera.exif.ExifInterface;
import com.android.camera.imageprocessor.filter.OptizoomFilter;
+import com.android.camera.imageprocessor.filter.SharpshooterFilter;
import com.android.camera.ui.RotateTextToast;
import java.io.ByteArrayOutputStream;
+import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;
+import java.util.TimeZone;
+
import com.android.camera.imageprocessor.filter.ImageFilter;
+import com.android.camera.util.CameraUtil;
public class PostProcessor implements ImageReader.OnImageAvailableListener{
@@ -62,7 +69,8 @@ public class PostProcessor implements ImageReader.OnImageAvailableListener{
private static final String TAG = "PostProcessor";
public static final int FILTER_NONE = 0;
public static final int FILTER_OPTIZOOM = 1;
- public static final int FILTER_MAX = 2;
+ public static final int FILTER_SHARPSHOOTER = 2;
+ public static final int FILTER_MAX = 3;
private int mCurrentNumImage = 0;
private ImageFilter mFilter;
@@ -80,7 +88,7 @@ public class PostProcessor implements ImageReader.OnImageAvailableListener{
private WatchdogThread mWatchdog;
//This is for the debug feature.
- private static boolean DEBUG_FILTER = true; //TODO: This has to be false before releasing.
+ private static boolean DEBUG_FILTER = false;
private ImageFilter.ResultImage mDebugResultImage;
@Override
@@ -258,6 +266,9 @@ public class PostProcessor implements ImageReader.OnImageAvailableListener{
case FILTER_OPTIZOOM:
mFilter = new OptizoomFilter(mController);
break;
+ case FILTER_SHARPSHOOTER:
+ mFilter = new SharpshooterFilter(mController);
+ break;
}
}
@@ -363,6 +374,20 @@ public class PostProcessor implements ImageReader.OnImageAvailableListener{
});
}
+ private byte[] addExifTags(byte[] jpeg, int orientationInDegree) {
+ ExifInterface exif = new ExifInterface();
+ exif.addOrientationTag(orientationInDegree);
+ exif.addDateTimeStampTag(ExifInterface.TAG_DATE_TIME, System.currentTimeMillis(),
+ TimeZone.getDefault());
+ ByteArrayOutputStream jpegOut = new ByteArrayOutputStream();
+ try {
+ exif.writeExif(jpeg, jpegOut);
+ } catch (IOException e) {
+ Log.e(TAG, "Could not write EXIF", e);
+ }
+ return jpegOut.toByteArray();
+ }
+
private void clear() {
mCurrentNumImage = 0;
}
@@ -409,29 +434,32 @@ public class PostProcessor implements ImageReader.OnImageAvailableListener{
) {
Log.e(TAG, "Processed outRoi is not within picture range");
} else {
+ int orientation = CameraUtil.getJpegRotation(mController.getMainCameraId(), mController.getDisplayOrientation());
if(mFilter != null && DEBUG_FILTER) {
- bytes = nv21ToJpeg(mDebugResultImage);
+ bytes = nv21ToJpeg(mDebugResultImage, orientation);
mActivity.getMediaSaveService().addImage(
bytes, title + "_beforeApplyingFilter", date, null, mDebugResultImage.outRoi.width(), mDebugResultImage.outRoi.height(),
- 0, null, mediaSavedListener, contentResolver, "jpeg");
+ orientation, null, mediaSavedListener, contentResolver, "jpeg");
}
- bytes = nv21ToJpeg(resultImage);
- mController.updateThumbnailJpegData(bytes);
+ bytes = nv21ToJpeg(resultImage, orientation);
mActivity.getMediaSaveService().addImage(
bytes, title, date, null, resultImage.outRoi.width(), resultImage.outRoi.height(),
- 0, null, mediaSavedListener, contentResolver, "jpeg");
+ orientation, null, mediaSavedListener, contentResolver, "jpeg");
+ mController.updateThumbnailJpegData(bytes);
}
}
}
});
}
- private byte[] nv21ToJpeg(ImageFilter.ResultImage resultImage) {
+ private byte[] nv21ToJpeg(ImageFilter.ResultImage resultImage, int orientation) {
BitmapOutputStream bos = new BitmapOutputStream(1024);
YuvImage im = new YuvImage(resultImage.outBuffer.array(), ImageFormat.NV21,
resultImage.width, resultImage.height, new int[]{resultImage.stride, resultImage.stride});
im.compressToJpeg(resultImage.outRoi, 50, bos);
- return bos.getArray();
+ byte[] bytes = bos.getArray();
+ bytes = addExifTags(bytes, orientation);
+ return bytes;
}
private class BitmapOutputStream extends ByteArrayOutputStream {
diff --git a/src/com/android/camera/imageprocessor/filter/OptizoomFilter.java b/src/com/android/camera/imageprocessor/filter/OptizoomFilter.java
index 4773418de..9b5af29dc 100644
--- a/src/com/android/camera/imageprocessor/filter/OptizoomFilter.java
+++ b/src/com/android/camera/imageprocessor/filter/OptizoomFilter.java
@@ -45,7 +45,7 @@ public class OptizoomFilter implements ImageFilter{
private int mStrideY;
private int mStrideVU;
private static String TAG = "OptizoomFilter";
- private static final boolean DEBUG = true; //TODO: Have to be false before releasing.
+ private static final boolean DEBUG = false;
private int temp;
private static boolean mIsSupported = true;
private ByteBuffer mOutBuf;
diff --git a/src/com/android/camera/imageprocessor/filter/SharpshooterFilter.java b/src/com/android/camera/imageprocessor/filter/SharpshooterFilter.java
new file mode 100644
index 000000000..74469afc3
--- /dev/null
+++ b/src/com/android/camera/imageprocessor/filter/SharpshooterFilter.java
@@ -0,0 +1,172 @@
+/*
+Copyright (c) 2016, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.android.camera.imageprocessor.filter;
+
+import android.graphics.Rect;
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.CaptureResult;
+import android.util.Log;
+import android.util.Range;
+import android.util.Rational;
+
+import com.android.camera.CaptureModule;
+
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.List;
+
+public class SharpshooterFilter implements ImageFilter{
+ public static final int NUM_REQUIRED_IMAGE = 5;
+ private int mWidth;
+ private int mHeight;
+ private int mStrideY;
+ private int mStrideVU;
+ private static String TAG = "SharpshooterFilter";
+ private static final boolean DEBUG = false;
+ private int temp;
+ private static boolean mIsSupported = true;
+ private ByteBuffer mOutBuf;
+ private CaptureModule mModule;
+ private int mSenseValue = 0;
+ private long mExpoTime;
+
+ private static void Log(String msg) {
+ if(DEBUG) {
+ Log.d(TAG, msg);
+ }
+ }
+
+ public SharpshooterFilter(CaptureModule module) {
+ mModule = module;
+ }
+
+ private void getSenseUpperValue() {
+ if(mSenseValue == 0) {
+ Range<Integer> sensRange = mModule.getMainCameraCharacteristics().get(CameraCharacteristics.SENSOR_INFO_SENSITIVITY_RANGE);
+ mSenseValue = sensRange.getUpper();
+ }
+ }
+ @Override
+ public List<CaptureRequest> setRequiredImages(CaptureRequest.Builder builder) {
+ getSenseUpperValue();
+ mExpoTime = (mModule.getPreviewCaptureResult().get(CaptureResult.SENSOR_EXPOSURE_TIME)/2);
+ int isoValue = (mModule.getPreviewCaptureResult().get(CaptureResult.SENSOR_SENSITIVITY)).intValue()*2;
+ if(isoValue < mSenseValue) {
+ mSenseValue = isoValue;
+ }
+
+ List<CaptureRequest> list = new ArrayList<CaptureRequest>();
+ for(int i=0; i < NUM_REQUIRED_IMAGE; i++) {
+ builder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_OFF);
+ builder.set(CaptureRequest.SENSOR_EXPOSURE_TIME, new Long(mExpoTime));
+ builder.set(CaptureRequest.SENSOR_SENSITIVITY, mSenseValue);
+ list.add(builder.build());
+ }
+ return list;
+ }
+
+ @Override
+ public String getStringName() {
+ return "SharpshooterFilter";
+ }
+
+ @Override
+ public int getNumRequiredImage() {
+ return NUM_REQUIRED_IMAGE;
+ }
+
+ @Override
+ public void init(int width, int height, int strideY, int strideVU) {
+ Log("init");
+ mWidth = width/2*2;
+ mHeight = height/2*2;
+ mStrideY = strideY/2*2;
+ mStrideVU = strideVU/2*2;
+ mOutBuf = ByteBuffer.allocate(mStrideY*mHeight*3/2);
+ Log("width: "+mWidth+" height: "+mHeight+" strideY: "+mStrideY+" strideVU: "+mStrideVU);
+ nativeInit(mWidth, mHeight, mStrideY, mStrideVU,
+ 0, 0, mWidth, mHeight, NUM_REQUIRED_IMAGE);
+ }
+
+ @Override
+ public void deinit() {
+ Log("deinit");
+ mOutBuf = null;
+ nativeDeinit();
+ }
+
+ @Override
+ public void addImage(ByteBuffer bY, ByteBuffer bVU, int imageNum, Object param) {
+ Log("addImage");
+ int yActualSize = bY.remaining();
+ int vuActualSize = bVU.remaining();
+ int status = nativeAddImage(bY, bVU, yActualSize, vuActualSize, imageNum);
+ if(status != 0) {
+ Log.e(TAG, "Fail to add image");
+ }
+ }
+
+ @Override
+ public ResultImage processImage() {
+ Log("processImage ");
+ int[] roi = new int[4];
+ int status = nativeProcessImage(mOutBuf.array(), (int) (mExpoTime / 1000000), mSenseValue, roi);
+ Log("processImage done");
+ if(status < 0) { //In failure case, library will return the first image as it is.
+ Log.w(TAG, "Fail to process the image.");
+ }
+ return new ResultImage(mOutBuf, new Rect(roi[0], roi[1], roi[0]+roi[2], roi[1] + roi[3]), mWidth, mHeight, mStrideY);
+ }
+
+ @Override
+ public boolean isSupported() {
+ return mIsSupported;
+ }
+
+ public static boolean isSupportedStatic() {
+ return mIsSupported;
+ }
+
+ private native int nativeInit(int width, int height, int yStride, int vuStride,
+ int roiX, int roiY, int roiW, int roiH, int numImages);
+ private native int nativeDeinit();
+ private native int nativeAddImage(ByteBuffer yB, ByteBuffer vuB, int ySize, int vuSize, int imageNum);
+ private native int nativeProcessImage(byte[] buffer, int expoTime, int isoValue, int[] roi);
+
+ static {
+ try {
+ System.loadLibrary("jni_sharpshooter");
+ mIsSupported = true;
+ }catch(UnsatisfiedLinkError e) {
+ Log.d(TAG, e.toString());
+ mIsSupported = false;
+ }
+ }
+}