summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorCamera Software Integration <camswint@localhost>2017-05-08 16:22:36 +0530
committerCamera Software Integration <camswint@localhost>2017-05-08 16:22:36 +0530
commit4c861ed100561fe2ebc6c890a891a17ffa3c418d (patch)
tree7d0dce995b832f468d93d27e44589adc09e13e28 /src
parent9cce1f7eb64e767266641fc18b831219861aa16d (diff)
parentd35d20015170337d5b6092e852b2f54fde487ce3 (diff)
downloadandroid_packages_apps_Snap-4c861ed100561fe2ebc6c890a891a17ffa3c418d.tar.gz
android_packages_apps_Snap-4c861ed100561fe2ebc6c890a891a17ffa3c418d.tar.bz2
android_packages_apps_Snap-4c861ed100561fe2ebc6c890a891a17ffa3c418d.zip
Merge tag 'camera.lnx.2.0-00010' into camera.lnx.3.0-dev
Merge tag 'camera.lnx.2.0-00010' into camera.lnx.3.0-dev Change-Id: I7e8e12e01f16093e1bda744de511c29e1ec26570
Diffstat (limited to 'src')
-rwxr-xr-xsrc/com/android/camera/AndroidCameraManagerImpl.java1
-rwxr-xr-x[-rw-r--r--]src/com/android/camera/CaptureModule.java27
-rw-r--r--src/com/android/camera/FocusOverlayManager.java2
-rw-r--r--src/com/android/camera/MediaSaveService.java183
-rwxr-xr-xsrc/com/android/camera/PhotoModule.java9
-rwxr-xr-xsrc/com/android/camera/SettingsManager.java1
-rw-r--r--src/com/android/camera/imageprocessor/PostProcessor.java1
-rw-r--r--src/com/android/camera/imageprocessor/filter/StillmoreFilter.java12
-rw-r--r--src/com/android/camera/util/PersistUtil.java40
-rw-r--r--src/com/android/camera/util/XmpUtil.java230
-rw-r--r--src/org/codeaurora/snapcam/filter/ClearSightImageProcessor.java328
-rw-r--r--src/org/codeaurora/snapcam/filter/ClearSightNativeEngine.java4
-rw-r--r--src/org/codeaurora/snapcam/filter/DDMNativeEngine.java396
-rw-r--r--src/org/codeaurora/snapcam/filter/GDepth.java307
-rw-r--r--src/org/codeaurora/snapcam/filter/GImage.java68
15 files changed, 1554 insertions, 55 deletions
diff --git a/src/com/android/camera/AndroidCameraManagerImpl.java b/src/com/android/camera/AndroidCameraManagerImpl.java
index 7c2bb836e..acb474afd 100755
--- a/src/com/android/camera/AndroidCameraManagerImpl.java
+++ b/src/com/android/camera/AndroidCameraManagerImpl.java
@@ -442,7 +442,6 @@ class AndroidCameraManagerImpl implements CameraManager {
}
return;
}
- throw e;
}
}
}
diff --git a/src/com/android/camera/CaptureModule.java b/src/com/android/camera/CaptureModule.java
index 346a818d3..60fb57168 100644..100755
--- a/src/com/android/camera/CaptureModule.java
+++ b/src/com/android/camera/CaptureModule.java
@@ -76,6 +76,7 @@ import android.provider.MediaStore;
import android.util.Log;
import android.util.Range;
import android.util.Size;
+import android.view.Gravity;
import android.view.KeyEvent;
import android.view.OrientationEventListener;
import android.view.Surface;
@@ -147,10 +148,10 @@ public class CaptureModule implements CameraModule, PhotoController,
public static final int INTENT_MODE_CAPTURE_SECURE = 3;
private static final int BACK_MODE = 0;
private static final int FRONT_MODE = 1;
- private static final int CANCEL_TOUCH_FOCUS_DELAY = 5000;
+ private static final int CANCEL_TOUCH_FOCUS_DELAY = PersistUtil.getCancelTouchFocusDelay();
private static final int OPEN_CAMERA = 0;
private static final int CANCEL_TOUCH_FOCUS = 1;
- private static final int MAX_NUM_CAM = 3;
+ private static final int MAX_NUM_CAM = 4;
private static final MeteringRectangle[] ZERO_WEIGHT_3A_REGION = new MeteringRectangle[]{
new MeteringRectangle(0, 0, 0, 0, 0)};
private static final String EXTRA_QUICK_CAPTURE =
@@ -753,6 +754,9 @@ public class CaptureModule implements CameraModule, PhotoController,
break;
}
case STATE_WAITING_TOUCH_FOCUS:
+ Integer afState = result.get(CaptureResult.CONTROL_AF_STATE);
+ Integer aeState = result.get(CaptureResult.CONTROL_AE_STATE);
+ Log.d(TAG, "STATE_WAITING_TOUCH_FOCUS id: " + id + " afState:" + afState + " aeState:" + aeState);
break;
}
}
@@ -4077,8 +4081,17 @@ public class CaptureModule implements CameraModule, PhotoController,
mCaptureSession[id].capture(mPreviewRequestBuilder[id]
.build(), mCaptureCallback, mCameraHandler);
} else {
- mCaptureSession[id].setRepeatingRequest(mPreviewRequestBuilder[id]
- .build(), mCaptureCallback, mCameraHandler);
+ CameraCaptureSession session = mCaptureSession[id];
+ if (session instanceof CameraConstrainedHighSpeedCaptureSession) {
+ List list = CameraUtil
+ .createHighSpeedRequestList(mPreviewRequestBuilder[id].build(),id);
+ ((CameraConstrainedHighSpeedCaptureSession) session).setRepeatingBurst(list
+ , mCaptureCallback, mCameraHandler);
+ } else {
+ mCaptureSession[id].setRepeatingRequest(mPreviewRequestBuilder[id]
+ .build(), mCaptureCallback, mCameraHandler);
+ }
+
}
} catch (CameraAccessException | IllegalStateException e) {
e.printStackTrace();
@@ -4411,6 +4424,7 @@ public class CaptureModule implements CameraModule, PhotoController,
updateVideoFlash();
return;
case SettingsManager.KEY_FLASH_MODE:
+ case SettingsManager.KEY_ZSL:
case SettingsManager.KEY_AUTO_HDR:
case SettingsManager.KEY_SAVERAW:
case SettingsManager.KEY_HDR:
@@ -4682,6 +4696,7 @@ public class CaptureModule implements CameraModule, PhotoController,
@Override
public void onClearSightSuccess(byte[] thumbnailBytes) {
Log.d(TAG, "onClearSightSuccess");
+ onReleaseShutterLock();
if(thumbnailBytes != null) mActivity.updateThumbnail(thumbnailBytes);
mActivity.runOnUiThread(new Runnable() {
@Override
@@ -4704,8 +4719,7 @@ public class CaptureModule implements CameraModule, PhotoController,
}
});
- unlockFocus(BAYER_ID);
- unlockFocus(MONO_ID);
+ onReleaseShutterLock();
}
/**
@@ -4859,6 +4873,7 @@ public class CaptureModule implements CameraModule, PhotoController,
private void showToast(String tips) {
if (mToast == null) {
mToast = Toast.makeText(mActivity, tips, Toast.LENGTH_LONG);
+ mToast.setGravity(Gravity.CENTER, 0, 0);
}
mToast.setText(tips);
mToast.show();
diff --git a/src/com/android/camera/FocusOverlayManager.java b/src/com/android/camera/FocusOverlayManager.java
index a41ce7d95..253c08fb9 100644
--- a/src/com/android/camera/FocusOverlayManager.java
+++ b/src/com/android/camera/FocusOverlayManager.java
@@ -434,7 +434,7 @@ public class FocusOverlayManager {
mHandler.removeMessages(RESET_TOUCH_FOCUS);
}
- private void cancelAutoFocus() {
+ public void cancelAutoFocus() {
Log.v(TAG, "Cancel autofocus.");
// Reset the tap area before calling mListener.cancelAutofocus.
diff --git a/src/com/android/camera/MediaSaveService.java b/src/com/android/camera/MediaSaveService.java
index 973aed415..00f5a4777 100644
--- a/src/com/android/camera/MediaSaveService.java
+++ b/src/com/android/camera/MediaSaveService.java
@@ -16,6 +16,8 @@
package com.android.camera;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
import java.io.File;
import java.nio.ByteOrder;
@@ -23,7 +25,10 @@ import android.app.Service;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Intent;
+import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
+import android.graphics.Color;
+import android.graphics.Rect;
import android.location.Location;
import android.net.Uri;
import android.os.AsyncTask;
@@ -36,6 +41,14 @@ import com.android.camera.exif.ExifInterface;
import com.android.camera.mpo.MpoData;
import com.android.camera.mpo.MpoImageData;
import com.android.camera.mpo.MpoInterface;
+import com.android.camera.util.XmpUtil;
+
+import org.codeaurora.snapcam.filter.GDepth;
+import org.codeaurora.snapcam.filter.GImage;
+
+import com.adobe.xmp.XMPException;
+import com.adobe.xmp.XMPMeta;
+
/*
* Service for saving images in the background thread.
@@ -148,6 +161,25 @@ public class MediaSaveService extends Service {
t.execute();
}
+ public void addClearsightImage(byte[] clearsight, GImage bayer, GDepth.DepthMap depthMap,
+ String title, long date, Location loc, int width, int height,
+ int orientation, ExifInterface exif,
+ OnMediaSavedListener l, ContentResolver resolver, String pictureFormat) {
+ if (isQueueFull()) {
+ Log.e(TAG, "Cannot add image when the queue is full");
+ return;
+ }
+ ClearsightImageSaveTask t = new ClearsightImageSaveTask(clearsight, bayer, depthMap,
+ title, date, (loc == null) ? null : new Location(loc),
+ width, height, orientation, exif, resolver, l, pictureFormat);
+
+ mMemoryUse += clearsight.length;
+ if (isQueueFull()) {
+ onQueueFull();
+ }
+ t.execute();
+ }
+
public void addImage(final byte[] data, String title, long date, Location loc,
int orientation, ExifInterface exif,
OnMediaSavedListener l, ContentResolver resolver) {
@@ -350,6 +382,157 @@ public class MediaSaveService extends Service {
}
}
+ private class ClearsightImageSaveTask extends AsyncTask <Void, Void, Uri> {
+ private byte[] clearsight;
+ private byte[] depth;
+ private GImage bayer;
+ private GDepth.DepthMap depthMap;
+ private GDepth gDepth;
+ private byte[] data;
+ private String title;
+ private long date;
+ private Location loc;
+ private int width, height;
+ private int orientation;
+ private ExifInterface exif;
+ private ContentResolver resolver;
+ private OnMediaSavedListener listener;
+ private String pictureFormat;
+
+ public ClearsightImageSaveTask(byte[] clearsight, GImage bayer,GDepth.DepthMap depthMap,
+ String title, long date, Location loc,
+ int width, int height, int orientation,
+ ExifInterface exif, ContentResolver resolver,
+ OnMediaSavedListener listener, String pictureFormat) {
+ this.clearsight = clearsight;
+ this.bayer = bayer;
+ this.depthMap = depthMap;
+ this.title = title;
+ this.date = date;
+ this.loc = loc;
+ this.width = width;
+ this.height = height;
+ this.orientation = orientation;
+ this.exif = exif;
+ this.resolver = resolver;
+ this.listener = listener;
+ this.pictureFormat = pictureFormat;
+
+ gDepth = null;
+ }
+
+ @Override
+ protected void onPreExecute() {
+ // do nothing.
+ }
+
+ @Override
+ protected Uri doInBackground(Void... v) {
+ if ( depthMap != null ) {
+ depthMap.buffer = converToJpegByte(depthMap.rawDepth, depthMap.width, depthMap.height);
+ gDepth = GDepth.createGDepth(depthMap);
+ }
+ data = embedGDepthAndBayerInClearSight(clearsight);
+ if ( data == null ) {
+ data = clearsight;
+ Log.e(TAG, "embedGDepthAndBayerInClearSight fail");
+ }
+
+ if (width == 0 || height == 0) {
+ // Decode bounds
+ BitmapFactory.Options options = new BitmapFactory.Options();
+ options.inJustDecodeBounds = true;
+ BitmapFactory.decodeByteArray(data, 0, data.length, options);
+ width = options.outWidth;
+ height = options.outHeight;
+ }
+ return Storage.addImage(
+ resolver, title, date, loc, orientation, exif, data, width, height, pictureFormat);
+ }
+
+ @Override
+ protected void onPostExecute(Uri uri) {
+ if (listener != null) listener.onMediaSaved(uri);
+ boolean previouslyFull = isQueueFull();
+ mMemoryUse -= data.length;
+ if (isQueueFull() != previouslyFull) onQueueAvailable();
+ }
+
+ private byte[] converToJpegByte(byte[] depthBuf, int width, int height) {
+ int[] colors = new int[depthBuf.length];
+ for(int i=0; i < colors.length; ++i) {
+ colors[i] = (256+depthBuf[i])%256;
+ }
+ Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
+ for( int y=0; y < height; ++y ) {
+ for( int x=0; x < width; ++x) {
+ int c = colors[y*width+x];
+ bitmap.setPixel(x, y, Color.rgb(c, c, c));
+ }
+ }
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ bitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos);
+ return baos.toByteArray();
+ }
+
+ private byte[] embedGDepthAndBayerInClearSight(byte[] clearSightImageBytes) {
+ Log.d(TAG, "embedGDepthInClearSight");
+ if ( clearSightImageBytes == null || (gDepth ==null && bayer==null) ) {
+ Log.d(TAG, "clearSightImageBytes is null");
+ return null;
+ }
+
+ XMPMeta xmpMeta = XmpUtil.createXMPMeta();
+ try {
+ if ( gDepth != null ) {
+ xmpMeta.setProperty(GDepth.NAMESPACE_URL, GDepth.PROPERTY_MIME, gDepth.getMime());
+ xmpMeta.setProperty(GDepth.NAMESPACE_URL, GDepth.PROPERTY_NEAR, gDepth.getNear());
+ xmpMeta.setProperty(GDepth.NAMESPACE_URL, GDepth.PROPERTY_FAR, gDepth.getFar());
+ xmpMeta.setProperty(GDepth.NAMESPACE_URL, GDepth.PROPERTY_FORMAT, gDepth.getFormat());
+ //extend for ROI
+ Rect roi = gDepth.getRoi();
+ xmpMeta.setProperty(GDepth.NAMESPACE_URL, GDepth.PROPERTY_ROI_X, roi.left);
+ xmpMeta.setProperty(GDepth.NAMESPACE_URL, GDepth.PROPERTY_ROI_Y, roi.top);
+ xmpMeta.setProperty(GDepth.NAMESPACE_URL, GDepth.PROPERTY_ROI_WIDTH, roi.width());
+ xmpMeta.setProperty(GDepth.NAMESPACE_URL, GDepth.PROPERTY_ROI_HEIGHT, roi.height());
+ }
+
+ if ( bayer != null ) {
+ xmpMeta.setProperty(GImage.NAMESPACE_URL, GImage.PROPERTY_MIME, bayer.getMime());
+ }
+
+
+ } catch(XMPException exception) {
+ Log.d(TAG, "create XMPMeta error", exception);
+ return null;
+ }
+
+ XMPMeta extendXmpMeta = XmpUtil.createXMPMeta();
+ try{
+ if ( gDepth != null) {
+ extendXmpMeta.setProperty(GDepth.NAMESPACE_URL, GDepth.PROPERTY_DATA, gDepth.getData());
+ }
+
+ if ( bayer != null ) {
+ extendXmpMeta.setProperty(GImage.NAMESPACE_URL, GImage.PROPERTY_DATA, bayer.getData());
+ }
+ }catch(XMPException exception) {
+ Log.d(TAG, "create extended XMPMeta error", exception);
+ }
+
+
+ ByteArrayInputStream bais = new ByteArrayInputStream(clearSightImageBytes);
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ if ( XmpUtil.writeXMPMeta(bais, baos, xmpMeta, extendXmpMeta) ){
+ return baos.toByteArray();
+ }else{
+ Log.e(TAG, "embedGDepthInClearSight failure ");
+ return null;
+ }
+
+ }
+ }
+
private class VideoSaveTask extends AsyncTask <Void, Void, Uri> {
private String path;
private long duration;
diff --git a/src/com/android/camera/PhotoModule.java b/src/com/android/camera/PhotoModule.java
index 7a8d1f6d6..3315973a6 100755
--- a/src/com/android/camera/PhotoModule.java
+++ b/src/com/android/camera/PhotoModule.java
@@ -5009,6 +5009,10 @@ public class PhotoModule
if (mPaused) return index;
mZoomValue = index;
if (mParameters == null || mCameraDevice == null) return index;
+ if ( mFocusManager != null
+ && mFocusManager.getCurrentFocusState() == FocusOverlayManager.STATE_FOCUSING ) {
+ mFocusManager.cancelAutoFocus();
+ }
// Set zoom parameters asynchronously
synchronized (mCameraDevice) {
mParameters.setZoom(mZoomValue);
@@ -5021,7 +5025,10 @@ public class PhotoModule
@Override
public void onZoomChanged(float requestedZoom) {
-
+ if ( mFocusManager != null
+ && mFocusManager.getCurrentFocusState() == FocusOverlayManager.STATE_FOCUSING ) {
+ mFocusManager.cancelAutoFocus();
+ }
}
@Override
diff --git a/src/com/android/camera/SettingsManager.java b/src/com/android/camera/SettingsManager.java
index 1f05e3c6e..7119ed0cb 100755
--- a/src/com/android/camera/SettingsManager.java
+++ b/src/com/android/camera/SettingsManager.java
@@ -149,6 +149,7 @@ public class SettingsManager implements ListMenu.SettingsListener {
public static final HashMap<String, Integer> KEY_ISO_INDEX = new HashMap<String, Integer>();
public static final String KEY_BSGC_DETECTION = "pref_camera2_bsgc_key";
+ public static final String KEY_ZSL = "pref_camera2_zsl_key";
private static final String TAG = "SnapCam_SettingsManager";
diff --git a/src/com/android/camera/imageprocessor/PostProcessor.java b/src/com/android/camera/imageprocessor/PostProcessor.java
index 5513b69bb..b78852182 100644
--- a/src/com/android/camera/imageprocessor/PostProcessor.java
+++ b/src/com/android/camera/imageprocessor/PostProcessor.java
@@ -673,6 +673,7 @@ public class PostProcessor{
mSaveRaw = isSaveRaw;
if(setFilter(postFilterId) || isFlashModeOn || isTrackingFocusOn || isMakeupOn || isSelfieMirrorOn
|| PersistUtil.getCameraZSLDisabled()
+ || "disable".equals(SettingsManager.getInstance().getValue(SettingsManager.KEY_ZSL))
|| "enable".equals(
SettingsManager.getInstance().getValue(SettingsManager.KEY_AUTO_HDR))
|| SettingsManager.getInstance().isCamera2HDRSupport()
diff --git a/src/com/android/camera/imageprocessor/filter/StillmoreFilter.java b/src/com/android/camera/imageprocessor/filter/StillmoreFilter.java
index 2f483bfdc..34784faa0 100644
--- a/src/com/android/camera/imageprocessor/filter/StillmoreFilter.java
+++ b/src/com/android/camera/imageprocessor/filter/StillmoreFilter.java
@@ -38,13 +38,14 @@ import android.util.Log;
import android.util.Range;
import com.android.camera.CaptureModule;
+import com.android.camera.util.PersistUtil;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;
public class StillmoreFilter implements ImageFilter{
- public static final int NUM_REQUIRED_IMAGE = 5;
+ public static final int NUM_REQUIRED_IMAGE = PersistUtil.getStillmoreNumRequiredImages();
private int mWidth;
private int mHeight;
private int mStrideY;
@@ -99,6 +100,13 @@ public class StillmoreFilter implements ImageFilter{
Log("width: "+mWidth+" height: "+mHeight+" strideY: "+mStrideY+" strideVU: "+mStrideVU);
nativeInit(mWidth, mHeight, mStrideY, mStrideVU,
0, 0, mWidth, mHeight, NUM_REQUIRED_IMAGE);
+ float brColor = PersistUtil.getStillmoreBrColor();
+ float brIntensity = PersistUtil.getStillmoreBrIntensity();
+ float smoothingintensity = PersistUtil.getStillmoreSmoothingIntensity();
+ nativeConfigureStillMore(brColor, brIntensity, smoothingintensity);
+ Log("ConfigureStillmore brColor: " + brColor + " brIntensity: " +
+ brIntensity + " smoothingintensity: " + smoothingintensity +
+ " NUM_REQUIRED_IMAGE: " + NUM_REQUIRED_IMAGE);
}
@Override
@@ -156,6 +164,8 @@ public class StillmoreFilter implements ImageFilter{
return mIsSupported;
}
+ private native int nativeConfigureStillMore(float brColor, float brIntensity,
+ float smoothingintensity);
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();
diff --git a/src/com/android/camera/util/PersistUtil.java b/src/com/android/camera/util/PersistUtil.java
index d0b936bbc..4a25c1457 100644
--- a/src/com/android/camera/util/PersistUtil.java
+++ b/src/com/android/camera/util/PersistUtil.java
@@ -46,6 +46,18 @@ public class PersistUtil {
SystemProperties.getBoolean("persist.sys.camera.zsl.disabled", false);
private static final int PERSIST_CAMERA2_DEBUG =
SystemProperties.getInt("persist.sys.camera2.debug", 0);
+ private static final int PERSIST_CAMERA_CANCEL_TOUCHFOCUS_DELAY =
+ SystemProperties.getInt("persist.camera.focus_delay", 5000);
+ private static final int PERSIST_CAMERA_DEBUG =
+ SystemProperties.getInt("persist.camera.debug", 0);
+ private static final String PERSIST_CAMERA_STILLMORE_BRCOLR =
+ SystemProperties.get("persist.camera.stm_brcolor", "0.5");
+ private static final String PERSIST_CAMERA_STILLMORE_BRINTENSITY =
+ SystemProperties.get("persist.camera.stm_brintensity", "0.6");
+ private static final String PERSIST_CAMERA_STILLMORE_SMOOTHINGINTENSITY =
+ SystemProperties.get("persist.camera.stm_smooth", "0");
+ private static final int PERSIST_CAMERA_STILLMORE_NUM_REQUIRED_IMAGE =
+ SystemProperties.getInt("persist.camera.stm_img_nums", 5);
public static final int CAMERA2_DEBUG_DUMP_IMAGE = 1;
public static final int CAMERA2_DEBUG_DUMP_LOG = 2;
@@ -76,6 +88,32 @@ public class PersistUtil {
}
public static int getCamera2Debug() {
- return PERSIST_CAMERA2_DEBUG;
+ return PERSIST_CAMERA_DEBUG;
+ }
+
+ public static float getStillmoreBrColor(){
+ float brColor = Float.parseFloat(PERSIST_CAMERA_STILLMORE_BRCOLR);
+ return brColor = (brColor < 0 || brColor > 1) ? 0.5f : brColor;
+ }
+
+ public static float getStillmoreBrIntensity(){
+ float brIntensity = Float.parseFloat(PERSIST_CAMERA_STILLMORE_BRINTENSITY);
+ return brIntensity = (brIntensity < 0 || brIntensity > 1) ? 0.6f : brIntensity;
+ }
+
+ public static float getStillmoreSmoothingIntensity(){
+ float smoothingIntensity = Float.parseFloat(PERSIST_CAMERA_STILLMORE_SMOOTHINGINTENSITY);
+ return smoothingIntensity = (smoothingIntensity < 0 || smoothingIntensity > 1) ?
+ 0f : smoothingIntensity;
+ }
+
+ public static int getStillmoreNumRequiredImages() {
+ return (PERSIST_CAMERA_STILLMORE_NUM_REQUIRED_IMAGE < 3 ||
+ PERSIST_CAMERA_STILLMORE_NUM_REQUIRED_IMAGE > 5) ?
+ 5 : PERSIST_CAMERA_STILLMORE_NUM_REQUIRED_IMAGE;
+ }
+
+ public static int getCancelTouchFocusDelay() {
+ return PERSIST_CAMERA_CANCEL_TOUCHFOCUS_DELAY;
}
}
diff --git a/src/com/android/camera/util/XmpUtil.java b/src/com/android/camera/util/XmpUtil.java
index c985a6bd8..5fcfa1aa5 100644
--- a/src/com/android/camera/util/XmpUtil.java
+++ b/src/com/android/camera/util/XmpUtil.java
@@ -30,7 +30,11 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
+import java.nio.ByteBuffer;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
+import java.util.Formatter;
import java.util.List;
/**
@@ -52,6 +56,13 @@ public class XmpUtil {
private static final String XMP_HEADER = "http://ns.adobe.com/xap/1.0/\0";
private static final int MAX_XMP_BUFFER_SIZE = 65502;
+ private static final String EXTENDED_XMP_HEADER_SIGNATURE = "http://ns.adobe.com/xmp/extension/\0";
+ private static final String XMP_NOTE_NAMESPACE = "http://ns.adobe.com/xmp/note/";
+ private static final String NOTE_PREFIX = "xmpNote";
+
+ private static final int MAX_EXTENDED_XMP_BUFFER_SIZE = 65000;
+ private static final int EXTEND_XMP_HEADER_SIZE = 75;
+
private static final String GOOGLE_PANO_NAMESPACE = "http://ns.google.com/photos/1.0/panorama/";
private static final String PANO_PREFIX = "GPano";
@@ -71,6 +82,9 @@ public class XmpUtil {
try {
XMPMetaFactory.getSchemaRegistry().registerNamespace(
GOOGLE_PANO_NAMESPACE, PANO_PREFIX);
+
+ XMPMetaFactory.getSchemaRegistry().registerNamespace(
+ XMP_NOTE_NAMESPACE, NOTE_PREFIX);
} catch (XMPException e) {
e.printStackTrace();
}
@@ -401,5 +415,221 @@ public class XmpUtil {
}
}
+ private static Section createStandardXMPSection(XMPMeta meta) {
+ byte[] buffer;
+ try {
+ SerializeOptions options = new SerializeOptions();
+ options.setUseCompactFormat(true);
+ // We have to omit packet wrapper here because
+ // javax.xml.parsers.DocumentBuilder
+ // fails to parse the packet end <?xpacket end="w"?> in android.
+ options.setOmitPacketWrapper(true);
+ buffer = XMPMetaFactory.serializeToBuffer(meta, options);
+ } catch (XMPException e) {
+ Log.d(TAG, "Serialize xmp failed", e);
+ return null;
+ }
+ if (buffer.length > MAX_XMP_BUFFER_SIZE) {
+ Log.e(TAG, "exceed max size");
+ return null;
+ }
+ // The XMP section starts with XMP_HEADER and then the real xmp data.
+ byte[] xmpdata = new byte[buffer.length + XMP_HEADER_SIZE];
+ System.arraycopy(XMP_HEADER.getBytes(), 0, xmpdata, 0, XMP_HEADER_SIZE);
+ System.arraycopy(buffer, 0, xmpdata, XMP_HEADER_SIZE, buffer.length);
+ Section xmpSection = new Section();
+ xmpSection.marker = M_APP1;
+ // Adds the length place (2 bytes) to the section length.
+ xmpSection.length = xmpdata.length + 2;
+ xmpSection.data = xmpdata;
+
+ return xmpSection;
+ }
+
+ private static Section createSection(byte[] portionOfExtendedMeta, byte[] headerBytes) {
+
+ if (portionOfExtendedMeta.length > MAX_EXTENDED_XMP_BUFFER_SIZE) {
+ // Do not support extended xmp now.
+ Log.e(TAG, "createSection fail exceed max size");
+ return null;
+ }
+
+ byte[] xmpdata = new byte[portionOfExtendedMeta.length + 75];
+ System.arraycopy(headerBytes, 0, xmpdata, 0, headerBytes.length);
+
+ System.arraycopy(portionOfExtendedMeta, 0, xmpdata, headerBytes.length, portionOfExtendedMeta.length);
+ Section xmpSection = new Section();
+ xmpSection.marker = M_APP1;
+ // Adds the length place (2 bytes) to the section length.
+ xmpSection.length = xmpdata.length + 2;
+ xmpSection.data = xmpdata;
+ ByteBuffer byteBuffer2 = ByteBuffer.wrap(xmpdata);
+ Log.d(TAG, "fullLength=" + byteBuffer2.getInt(67) + " offset=" + byteBuffer2.getInt(71));
+ return xmpSection;
+ }
+
+ /**
+ * Split extendXMPMeta to multiple marker segments
+ * @param extendedXMPMetaBytes serialized extended XMP
+ * @param guid Is a 128-bit MD5 digest of the full ExtendedXMP serialization,
+ * stored as a 32-byte ASCII hex string
+ * @return split result
+ */
+ private static List<Section> splitExtendXMPMeta(byte[] extendedXMPMetaBytes, String guid){
+ List<Section> sections = new ArrayList<Section>();
+ /*
+ The extended XMP JPEG marker segment content holds:
+ - a signature string, "http://ns.adobe.com/xmp/extension/\0"
+ - a 128 bit GUID stored as a 32 byte ASCII hex string
+ - a UInt32 full length of the entire extended XMP
+ - a UInt32 offset for this portion of the extended XMP
+ - the UTF-8 text for this portion of the extended XMP
+ */
+ int splitNum = extendedXMPMetaBytes.length/MAX_EXTENDED_XMP_BUFFER_SIZE;
+ byte[] portion = new byte[MAX_EXTENDED_XMP_BUFFER_SIZE];
+ ByteBuffer byteBuffer = ByteBuffer.wrap(extendedXMPMetaBytes);
+ Section extendedXmpSection = null;
+
+ byte[] headerBytes = new byte[EXTEND_XMP_HEADER_SIZE];
+ int index = 0;
+ System.arraycopy(EXTENDED_XMP_HEADER_SIGNATURE.getBytes(), 0, headerBytes, 0, EXTENDED_XMP_HEADER_SIGNATURE.length());
+ index += EXTENDED_XMP_HEADER_SIGNATURE.length();
+
+ System.arraycopy(guid.getBytes(), 0, headerBytes, index, guid.length());
+ index += guid.length();
+
+ Log.d(TAG, "buffer.length=" + extendedXMPMetaBytes.length);
+ byte[] fullLengthBytes = new byte[4];
+ ByteBuffer intBuffer = ByteBuffer.wrap(fullLengthBytes);
+ intBuffer.putInt(0, extendedXMPMetaBytes.length);
+ System.arraycopy(fullLengthBytes, 0, headerBytes, index, 4);
+ index += 4;
+
+ byte[] offsetBytes = new byte[4];
+ ByteBuffer offsetBuffer = ByteBuffer.wrap(offsetBytes);
+ for( int i=0; i < splitNum; ++i ) {
+ offsetBuffer.putInt(0, i*MAX_EXTENDED_XMP_BUFFER_SIZE);
+ System.arraycopy(offsetBytes, 0, headerBytes, index, 4);
+
+ byteBuffer.get(portion);
+ extendedXmpSection = createSection(portion, headerBytes);
+ sections.add(extendedXmpSection);
+ }
+
+ int remainSize = extendedXMPMetaBytes.length - splitNum*MAX_EXTENDED_XMP_BUFFER_SIZE;
+ if ( remainSize > 0 ) {
+ offsetBuffer.putInt(0, splitNum*MAX_EXTENDED_XMP_BUFFER_SIZE);
+ System.arraycopy(offsetBytes, 0, headerBytes, index, 4);
+
+ byte[] remain = new byte[remainSize];
+ byteBuffer.get(remain);
+ extendedXmpSection = createSection(remain, headerBytes);
+ sections.add(extendedXmpSection);
+ }
+
+ return sections;
+ }
+
+ /**
+ * Updates a jpeg file from inputStream with XMPMeta to outputStream.
+ * @param inputStream Input image data stream
+ * @param outputStream Output image data stream
+ * @param standardMeta The main portion of the metadata tree must be serialized and written as
+ * the standard XMP packet
+ * @param extendedMeta The extended portion must be serialized without a packet wrapper,
+ * and written as a series of APP1 marker segments
+ */
+ public static boolean writeXMPMeta(InputStream inputStream, OutputStream outputStream,
+ XMPMeta standardMeta, XMPMeta extendedMeta) {
+ byte[] buffer;
+ try {
+ SerializeOptions options = new SerializeOptions();
+ options.setUseCompactFormat(true);
+ // We have to omit packet wrapper here because
+ // javax.xml.parsers.DocumentBuilder
+ // fails to parse the packet end <?xpacket end="w"?> in android.
+ options.setOmitPacketWrapper(true);
+ buffer = XMPMetaFactory.serializeToBuffer(extendedMeta, options);
+ } catch (XMPException e) {
+ Log.d(TAG, "Serialize extended xmp failed", e);
+ return false;
+ }
+
+ String guid = getGUID(buffer);
+ try {
+ standardMeta.setProperty(XMP_NOTE_NAMESPACE, "HasExtendedXMP", guid);
+ } catch (XMPException exception) {
+ Log.d(TAG, "set XMPMeta Property", exception);
+ return false;
+ }
+ List<Section> sections = parse(inputStream, false);
+ List<Section> xmpSections = new ArrayList<Section>();
+ Section standardXmpSection = createStandardXMPSection(standardMeta);
+ if (standardXmpSection == null) {
+ Log.e(TAG, "create standard meta section error");
+ return false;
+ }
+ xmpSections.add(standardXmpSection);
+
+ List<Section> extendedSections = splitExtendXMPMeta(buffer, guid);
+ xmpSections.addAll(extendedSections);
+ sections = insertXMPSection(sections, xmpSections);
+ if (sections == null) {
+ Log.d(TAG, "Insert XMP fialed");
+ return false;
+ }
+ try {
+ // Overwrite the image file with the new meta data.
+ writeJpegFile(outputStream, sections);
+ } catch (IOException e) {
+ Log.d(TAG, "Write to stream failed", e);
+ return false;
+ } finally {
+ if (outputStream != null) {
+ try {
+ outputStream.close();
+ } catch (IOException e) {
+ // Ignore.
+ }
+ }
+ }
+ return true;
+ }
+
+ private static List<Section> insertXMPSection(
+ List<Section> sections, List<Section> xmpSections) {
+ if (sections == null || sections.size() <= 1) {
+ return null;
+ }
+
+ // If the first section is Exif, insert XMP data before the second section,
+ // otherwise, make xmp data the first section.
+ List<Section> newSections = new ArrayList<Section>();
+ int position = (sections.get(0).marker == M_APP1) ? 1 : 0;
+ newSections.addAll(sections.subList(0, position));
+ newSections.addAll(xmpSections);
+ newSections.addAll(sections.subList(position, sections.size()));
+ return newSections;
+ }
+
+ private static String getGUID(byte[] src) {
+ StringBuilder builder = new StringBuilder();
+ try {
+ MessageDigest digester = MessageDigest.getInstance("MD5");
+ digester.update(src);
+ byte[] digest = digester.digest();
+
+ Formatter formatter = new Formatter(builder);
+ for (int i = 0; i < digest.length; ++i) {
+ formatter.format("%02x", ((256 + digest[i]) % 256));
+ }
+ } catch (NoSuchAlgorithmException exception) {
+ Log.d(TAG, "get md5 instance failure" + exception);
+ return null;
+ }
+
+ return builder.toString().toUpperCase();
+ }
+
private XmpUtil() {}
}
diff --git a/src/org/codeaurora/snapcam/filter/ClearSightImageProcessor.java b/src/org/codeaurora/snapcam/filter/ClearSightImageProcessor.java
index b347586d7..91e450f71 100644
--- a/src/org/codeaurora/snapcam/filter/ClearSightImageProcessor.java
+++ b/src/org/codeaurora/snapcam/filter/ClearSightImageProcessor.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2017, 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
@@ -30,6 +30,10 @@
package org.codeaurora.snapcam.filter;
import java.io.ByteArrayOutputStream;
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.util.ArrayDeque;
import java.util.ArrayList;
@@ -38,8 +42,11 @@ import java.util.List;
import org.codeaurora.snapcam.filter.ClearSightNativeEngine.CamSystemCalibrationData;
import org.codeaurora.snapcam.filter.ClearSightNativeEngine.ClearsightImage;
+import org.codeaurora.snapcam.filter.DDMNativeEngine;
import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.Color;
import android.graphics.ImageFormat;
import android.graphics.Rect;
import android.graphics.YuvImage;
@@ -80,6 +87,7 @@ import com.android.camera.PhotoModule.NamedImages.NamedEntity;
import com.android.camera.Storage;
import com.android.camera.util.CameraUtil;
+
public class ClearSightImageProcessor {
private static final String TAG = "ClearSightImageProcessor";
private static final String PERSIST_TIMESTAMP_LIMIT_KEY = "persist.sys.camera.cs.threshold";
@@ -106,6 +114,9 @@ public class ClearSightImageProcessor {
private static final int MSG_NEW_REPROC_RESULT = 4;
private static final int MSG_NEW_REPROC_FAIL = 5;
private static final int MSG_END_CAPTURE = 6;
+ private static final int MSG_CALIBRATION_DATA = 7;
+ private static final int MSG_NEW_LENS_FOCUS_DISTANCE_BAYER = 8;
+ private static final int MSG_NEW_DEPTH = 9;
private static final int CAM_TYPE_BAYER = 0;
private static final int CAM_TYPE_MONO = 1;
@@ -115,6 +126,10 @@ public class ClearSightImageProcessor {
new CameraCharacteristics.Key<>(
"org.codeaurora.qcamera3.dualcam_calib_meta_data.dualcam_calib_meta_data_blob",
byte[].class);
+ private CaptureResult.Key<byte[]> SCALE_CROP_ROTATION_REPROCESS_BLOB =
+ new CaptureResult.Key<byte[]>(
+ "org.codeaurora.qcamera3.hal_private_data.reprocess_data_blob",
+ byte[].class);
private NamedImages mNamedImages;
private ImageReader[] mImageReader = new ImageReader[NUM_CAM];
@@ -128,10 +143,13 @@ public class ClearSightImageProcessor {
private ClearsightRegisterHandler mClearsightRegisterHandler;
private ClearsightProcessHandler mClearsightProcessHandler;
private ImageEncodeHandler mImageEncodeHandler;
+ private DepthProcessHandler mDepthProcessHandler;
+
private HandlerThread mImageProcessThread;
private HandlerThread mClearsightRegisterThread;
private HandlerThread mClearsightProcessThread;
private HandlerThread mImageEncodeThread;
+ private HandlerThread mDepthProcessThread;
private Callback mCallback;
private CameraCaptureSession[] mCaptureSessions = new CameraCaptureSession[NUM_CAM];
@@ -144,6 +162,7 @@ public class ClearSightImageProcessor {
private int mCsTimeout;
private boolean mDumpImages;
private boolean mDumpYUV;
+ private boolean mDumpDepth;
private boolean mIsClosing;
private int mFinishReprocessNum;
@@ -167,8 +186,12 @@ public class ClearSightImageProcessor {
mDumpYUV = SystemProperties.getBoolean(PERSIST_DUMP_YUV_KEY, false);
Log.d(TAG, "mDumpYUV: " + mDumpYUV);
+ mDumpDepth = SystemProperties.getBoolean(PERSIST_DUMP_DEPTH_KEY, false);
+ Log.d(TAG, "mDumpDepth: " + mDumpDepth);
+
mCsTimeout = SystemProperties.getInt(PERSIST_CS_TIMEOUT_KEY, DEFAULT_CS_TIMEOUT_MS);
Log.d(TAG, "mCsTimeout: " + mCsTimeout);
+
}
public static void createInstance() {
@@ -197,11 +220,14 @@ public class ClearSightImageProcessor {
mClearsightProcessThread.start();
mImageEncodeThread = new HandlerThread("CameraImageEncode");
mImageEncodeThread.start();
+ mDepthProcessThread = new HandlerThread("DepthProcess");
+ mDepthProcessThread.start();
mImageProcessHandler = new ImageProcessHandler(mImageProcessThread.getLooper());
mClearsightRegisterHandler = new ClearsightRegisterHandler(mClearsightRegisterThread.getLooper());
mClearsightProcessHandler = new ClearsightProcessHandler(mClearsightProcessThread.getLooper());
mImageEncodeHandler = new ImageEncodeHandler(mImageEncodeThread.getLooper());
+ mDepthProcessHandler = new DepthProcessHandler(mImageEncodeThread.getLooper());
mFinalPictureSize = new Size(width, height);
mFinalPictureRatio = (float)width / (float)height;
@@ -219,8 +245,11 @@ public class ClearSightImageProcessor {
try {
CameraCharacteristics cc = cm.getCameraCharacteristics("0");
byte[] blob = cc.get(OTP_CALIB_BLOB);
+ CamSystemCalibrationData calibrationData = CamSystemCalibrationData.createFromBytes(blob);
ClearSightNativeEngine.getInstance().init(mNumFrameCount*2,
- maxWidth, maxHeight, CamSystemCalibrationData.createFromBytes(blob));
+ maxWidth, maxHeight, calibrationData);
+ mDepthProcessHandler.obtainMessage(MSG_CALIBRATION_DATA,0, 0,
+ calibrationData).sendToTarget();
} catch (CameraAccessException e) {
e.printStackTrace();
}
@@ -281,6 +310,17 @@ public class ClearSightImageProcessor {
}
}
+ if ( mDepthProcessThread != null ) {
+ mDepthProcessThread.quit();
+ try{
+ mDepthProcessThread.join();
+ mDepthProcessThread = null;
+ mDepthProcessHandler = null;
+ }catch (InterruptedException e){
+ e.printStackTrace();
+ }
+ }
+
for(int i=0; i<mImageReader.length; i++) {
if (null != mImageReader[i]) {
mImageReader[i].close();
@@ -356,9 +396,16 @@ public class ClearSightImageProcessor {
Log.d(TAG, "capture - onCaptureCompleted: " + cam);
if(isClosing())
Log.d(TAG, "capture - onCaptureCompleted - closing");
- else
+ else {
mImageProcessHandler.obtainMessage(MSG_NEW_CAPTURE_RESULT,
cam, 0, result).sendToTarget();
+ if (cam == CAM_TYPE_BAYER) {
+ float lensFocusDistance = result.get(CaptureResult.LENS_FOCUS_DISTANCE);
+ Log.d(TAG, "lensFocusDistance=" + lensFocusDistance);
+ mDepthProcessHandler.obtainMessage(MSG_NEW_LENS_FOCUS_DISTANCE_BAYER,
+ 0, 0, lensFocusDistance).sendToTarget();
+ }
+ }
}
@Override
@@ -492,6 +539,7 @@ public class ClearSightImageProcessor {
mNamedEntity = mNamedImages.getNextNameEntity();
mClearsightRegisterHandler.obtainMessage(MSG_START_CAPTURE,
0, 0, mNamedEntity).sendToTarget();
+ mDepthProcessHandler.obtainMessage(MSG_START_CAPTURE).sendToTarget();
break;
case MSG_END_CAPTURE:
// TIMED OUT WAITING FOR FRAME
@@ -832,6 +880,8 @@ public class ClearSightImageProcessor {
// reference not yet set
Log.d(TAG, "reprocess - setReferenceResult: " + msg.obj);
ClearSightNativeEngine.getInstance().setReferenceResult(isBayer, result);
+ mDepthProcessHandler.obtainMessage(MSG_NEW_REPROC_RESULT, msg.arg1, 0, msg.obj)
+ .sendToTarget();
}
mFinishReprocessNum++;
checkReprocessDone();
@@ -912,6 +962,7 @@ public class ClearSightImageProcessor {
.hasReferenceImage(isBayer)) {
// reference not yet set
ClearSightNativeEngine.getInstance().setReferenceImage(isBayer, image);
+ mDepthProcessHandler.obtainMessage(MSG_NEW_IMG, msg.arg1, 0, msg.obj).sendToTarget();
} else {
// if ref images set, register this image
if(ClearSightNativeEngine.getInstance().registerImage(
@@ -960,9 +1011,6 @@ public class ClearSightImageProcessor {
ClearSightNativeEngine.getInstance().reset();
if(processInit) {
- if(mCallback != null)
- mCallback.onReleaseShutterLock();
-
Image encodeImage = mImageWriter[CAM_TYPE_BAYER].dequeueInputImage();
ClearSightNativeEngine.ClearsightImage csImage = new ClearsightImage(encodeImage);
encodeImage.setTimestamp(csTs);
@@ -1086,13 +1134,19 @@ public class ClearSightImageProcessor {
private short mEncodeRequest;
private short mEncodeResults;
- private boolean mReadyToSave;
private boolean mHasFailure;
private Image mMonoImage;
private Image mBayerImage;
private Image mClearSightImage;
private NamedEntity mNamedEntity;
+ private GDepth.DepthMap mDepthMap;
+ private GImage mGImage;
+ private boolean mDepthMapReady;
+ private boolean mClearSightReady;
+
+ private long CLEAR_SIGHT_IMAGE_SAVE_DELAY = 1*500;
+
public ImageEncodeHandler(Looper looper) {
super(looper);
}
@@ -1110,15 +1164,19 @@ public class ClearSightImageProcessor {
Log.d(TAG, "ImageEncodeEvent - END_CAPTURE");
mNamedEntity = (NamedEntity) msg.obj;
mEncodeRequest = (short)msg.arg1;
- mReadyToSave = true;
- saveMpoImage();
+ mClearSightReady = true;
+ saveClearSightImage();
break;
case MSG_NEW_IMG:
case MSG_NEW_CAPTURE_RESULT:
case MSG_NEW_CAPTURE_FAIL:
processNewEvent(msg);
- saveMpoImage();
+ saveClearSightImage();
break;
+ case MSG_NEW_DEPTH:
+ processNewGDepth(msg);
+ saveClearSightImage();
+ break;
}
}
@@ -1128,12 +1186,20 @@ public class ClearSightImageProcessor {
if(msg.arg1 == CAM_TYPE_MONO) {
mMonoImage = (Image)msg.obj;
mEncodeResults |= MASK_MONO_ENCODE;
+ if ( mDumpDepth ) {
+ saveToFile(getJpegData(mMonoImage), "mono", "jpg");
+ }
} else if(mBayerImage == null){
mBayerImage = (Image)msg.obj;
mEncodeResults |= MASK_BAYER_ENCODE;
+ mGImage = new GImage(getJpegData(mBayerImage), "image/jpeg");
+ if ( mDumpDepth ) {
+ saveToFile(getJpegData(mBayerImage), "bayer", "jpg");
+ }
} else {
mClearSightImage = (Image)msg.obj;
mEncodeResults |= MASK_CS_ENCODE;
+
}
} else if (msg.what == MSG_NEW_CAPTURE_RESULT) {
Log.d(TAG, "processNewEncodeEvent - newResult: " + msg.arg1);
@@ -1152,63 +1218,69 @@ public class ClearSightImageProcessor {
}
}
- private void saveMpoImage() {
- if(!mReadyToSave || mEncodeRequest != mEncodeResults) {
- Log.d(TAG, "saveMpoImage - not yet ready to save");
+ private void processNewGDepth(Message msg) {
+ mDepthMap = (GDepth.DepthMap)msg.obj;
+ mDepthMapReady = true;
+ }
+
+ private void saveClearSightImage() {
+ if ( !isReadyToSave() || mEncodeRequest != mEncodeResults) {
+ Log.d(TAG, "saveClearSightImage - not yet ready to save");
return;
}
- Log.d(TAG, "saveMpoImage");
if(mHasFailure) {
// don't save anything and fail
- Log.d(TAG, "saveMpoImage has failure - aborting.");
+ Log.d(TAG, "saveClearSightImage has failure - aborting.");
if(mCallback != null) mCallback.onClearSightFailure(null);
resetParams();
return;
}
+ Log.d(TAG, "saveClearSightImage");
+ byte[] clearSightBytes = getJpegData(mClearSightImage);
+
String title = (mNamedEntity == null) ? null : mNamedEntity.title;
long date = (mNamedEntity == null) ? -1 : mNamedEntity.date;
- int width = mBayerImage.getWidth();
- int height = mBayerImage.getHeight();
- if(mClearSightImage != null) {
+ int width = 0;
+ int height = 0;
+ if ( mBayerImage != null ) {
+ mBayerImage.getWidth();
+ mBayerImage.getHeight();
+ }
+ if ( mClearSightImage != null ) {
width = mClearSightImage.getWidth();
height = mClearSightImage.getHeight();
}
- byte[] clearSightBytes = getJpegData(mClearSightImage);
byte[] bayerBytes = getJpegData(mBayerImage);
- byte[] monoBytes = getJpegData(mMonoImage);
- ExifInterface exif = Exif.getExif(bayerBytes);
- int orientation = Exif.getOrientation(exif);
-
- if(clearSightBytes != null) {
- if(mCallback != null) mCallback.onClearSightSuccess(clearSightBytes);
- } else if (bayerBytes != null) {
- if(mCallback != null) mCallback.onClearSightFailure(bayerBytes);
- } else {
- if(mCallback != null) mCallback.onClearSightFailure(null);
- }
+ if ( bayerBytes != null ) {
+ ExifInterface exif = Exif.getExif(bayerBytes);
+ int orientation = Exif.getOrientation(exif);
+
+ if(clearSightBytes != null) {
+ if(mCallback != null) mCallback.onClearSightSuccess(clearSightBytes);
+ } else if (bayerBytes != null) {
+ if(mCallback != null) mCallback.onClearSightFailure(bayerBytes);
+ } else {
+ if(mCallback != null) mCallback.onClearSightFailure(null);
+ }
- if(monoBytes == null) {
- mMediaSaveService.addImage(
- clearSightBytes!=null?clearSightBytes:bayerBytes, title, date, null,
+ mMediaSaveService.addClearsightImage(
+ clearSightBytes != null ? clearSightBytes : bayerBytes,
+ mGImage, mDepthMap,title, date, null,
width, height, orientation, exif,
mMediaSavedListener,
mMediaSaveService.getContentResolver(), "jpeg");
- } else if (bayerBytes != null) {
- mMediaSaveService.addMpoImage(
- clearSightBytes,
- bayerBytes,
- monoBytes, width, height, title,
- date, null, orientation, mMediaSavedListener,
- mMediaSaveService.getContentResolver(), "jpeg");
}
-
resetParams();
}
+ private boolean isReadyToSave() {
+ return (mDepthMapReady &&mClearSightReady);
+ }
+
void resetParams() {
if(mBayerImage != null) {
mBayerImage.close();
@@ -1223,10 +1295,182 @@ public class ClearSightImageProcessor {
mClearSightImage = null;
}
mNamedEntity = null;
- mReadyToSave = false;
mHasFailure = false;
mEncodeRequest = 0;
mEncodeResults = 0;
+ mGImage = null;
+ mDepthMapReady = false;
+ mClearSightReady = false;
+ }
+ }
+
+ private class DepthProcessHandler extends Handler{
+ private TotalCaptureResult mReprocessCaptureResult;
+ private DDMNativeEngine mDDMNativeEngine;
+ public DepthProcessHandler(Looper looper) {
+ super(looper);
+ mDDMNativeEngine = new DDMNativeEngine();
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ switch( msg.what ) {
+ case MSG_CALIBRATION_DATA:
+ setCalibrationdata(msg);
+ break;
+
+ case MSG_NEW_LENS_FOCUS_DISTANCE_BAYER:
+ setBayerLensFocusDistance(msg);
+ break;
+
+ case MSG_START_CAPTURE:
+ resetParams();
+ break;
+
+ case MSG_NEW_IMG:
+ registerImage(msg);
+ break;
+
+ case MSG_NEW_REPROC_RESULT:
+ registerReprocessResult(msg);
+ break;
+ }
+ }
+
+ private void setCalibrationdata(Message msg) {
+ mDDMNativeEngine.setCamSystemCalibrationData((CamSystemCalibrationData)msg.obj);
+ }
+ private void resetParams(){
+ Log.d(TAG, "resetParams");
+ mDDMNativeEngine.reset();
+ }
+
+ private void setBayerLensFocusDistance(Message msg) {
+ mDDMNativeEngine.setBayerLensFocusDistance((float)msg.obj);
+ }
+
+ private void registerImage(Message msg) {
+ boolean isBayer = (msg.arg1 == CAM_TYPE_BAYER);
+ Image image = (Image) msg.obj;
+ if ( isBayer ) {
+ mDDMNativeEngine.setBayerImage(image);
+ }else{
+ mDDMNativeEngine.setMonoImage(image);
+ }
+
+ if ( mDDMNativeEngine.isReadyForGenerateDepth() ) {
+ generateDepthmap();
+ }
+ }
+
+ private void registerReprocessResult(Message msg) {
+
+ boolean isBayer = (msg.arg1 == CAM_TYPE_BAYER);
+ Log.d(TAG, "registerReprocessResult bayer=" + isBayer);
+ TotalCaptureResult result = (TotalCaptureResult)msg.obj;
+ if ( isBayer ) {
+ mDDMNativeEngine.setBayerReprocessResult(result);
+ }else{
+ mDDMNativeEngine.setMonoReprocessResult(result);
+ }
+
+ if ( mDDMNativeEngine.isReadyForGenerateDepth() ) {
+ generateDepthmap();
+ }
+
+ }
+
+ private void generateDepthmap() {
+ GDepth.DepthMap depthMap = null;
+ int[] size = new int[2];
+ if ( mDDMNativeEngine.getDepthMapSize(size) ) {
+ int width = size[0];
+ int height = size[1];
+ Bitmap bmp = Bitmap.createBitmap(width, height,
+ Bitmap.Config.ALPHA_8);
+ int stride = bmp.getRowBytes();
+ byte[] depthBuffer = new byte[stride*height];
+ Log.d(TAG, "depthMapWidth=" + width + " depthMapHeight="
+ + height + " stride=" + stride);
+ Rect roiRect = new Rect();
+
+ if ( mDDMNativeEngine.dualCameraGenerateDDM(depthBuffer, stride, roiRect) ) {
+ if ( mDumpDepth ) {
+ saveAsRGB(depthBuffer, width, height);
+ }
+ depthMap = new GDepth.DepthMap(width, height);
+ depthMap.roi = roiRect;
+ depthMap.rawDepth = depthBuffer;
+ }else{
+ Log.e(TAG, "dualCameraGenerateDDM failure");
+ }
+ }else{
+ Log.e(TAG, "getDepthMapSize failure");
+ }
+ if ( mDumpDepth ) {
+ dumpCameraParam();
+ }
+ mImageEncodeHandler.obtainMessage(MSG_NEW_DEPTH, 0, 0, depthMap).sendToTarget();
+ }
+
+ private void dumpCameraParam() {
+ saveToFile(mDDMNativeEngine.getOTPCalibration().getBytes(), "OTPdata", "txt");
+ saveToFile(mDDMNativeEngine.getBayerScaleCrop().getBytes(), "BayerScaleCrop", "txt");
+ saveToFile(mDDMNativeEngine.getMonoScaleCrop().getBytes(), "MonoScaleCrop", "txt");
+ }
+ }
+
+ private void saveAsRGB(byte[] depth, int width, int height) {
+ int[] colors = new int[depth.length];
+ for(int i=0; i < colors.length; ++i) {
+ colors[i] = (256+depth[i])%256;
+ }
+
+ Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
+ for( int y=0; y < height; ++y ) {
+ for( int x=0; x < width; ++x) {
+ int c = colors[y*width+x];
+ bitmap.setPixel(x, y, Color.rgb(c, c, c));
+ }
+ }
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ bitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos);
+ File file = new File("sdcard/depthmap_rgb.jpg");
+ byte[] jpeg = baos.toByteArray();
+ Log.d(TAG, "jpeg.size=" + jpeg.length);
+ OutputStream out = null;
+ try {
+ out = new BufferedOutputStream(new FileOutputStream(file));
+ out.write(jpeg, 0, jpeg.length);
+ }catch(Exception e) {
+ Log.d(TAG, e.toString());
+ }finally {
+ if (out != null) {
+ try {
+ out.close();
+ }catch(Exception e){
+ Log.d(TAG, e.toString());
+ }
+ }
+ }
+ }
+
+ private void saveToFile(byte[] bytes, String name, String format){
+ File file = new File("sdcard/"+ name + "." + format);
+ OutputStream out = null;
+ try {
+ out = new BufferedOutputStream(new FileOutputStream(file));
+ out.write(bytes, 0, bytes.length);
+ }catch(Exception e) {
+ Log.d(TAG, e.toString());
+ }finally {
+ if (out != null) {
+ try {
+ out.close();
+ }catch(Exception e){
+ Log.d(TAG, e.toString());
+ }
+ }
}
}
diff --git a/src/org/codeaurora/snapcam/filter/ClearSightNativeEngine.java b/src/org/codeaurora/snapcam/filter/ClearSightNativeEngine.java
index 402ffce84..8b30ca032 100644
--- a/src/org/codeaurora/snapcam/filter/ClearSightNativeEngine.java
+++ b/src/org/codeaurora/snapcam/filter/ClearSightNativeEngine.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2017, 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
@@ -412,7 +412,7 @@ public class ClearSightNativeEngine {
public static class CamSystemCalibrationData {
private static final String[] CALIB_FMT_STRINGS = {
- "Calibration OTP format version = %x\n",
+ "Calibration OTP format version = %d\n",
"Main Native Sensor Resolution width = %dpx\n",
"Main Native Sensor Resolution height = %dpx\n",
"Main Calibration Resolution width = %dpx\n",
diff --git a/src/org/codeaurora/snapcam/filter/DDMNativeEngine.java b/src/org/codeaurora/snapcam/filter/DDMNativeEngine.java
new file mode 100644
index 000000000..b2b0a523d
--- /dev/null
+++ b/src/org/codeaurora/snapcam/filter/DDMNativeEngine.java
@@ -0,0 +1,396 @@
+/*
+ * Copyright (c) 2017, 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 org.codeaurora.snapcam.filter;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+import android.graphics.Rect;
+import android.media.Image;
+import android.media.Image.Plane;
+import android.util.Log;
+
+import android.hardware.camera2.CaptureResult;
+import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.TotalCaptureResult;
+
+import org.codeaurora.snapcam.filter.ClearSightNativeEngine.CamSystemCalibrationData;
+
+public class DDMNativeEngine {
+ private static final String TAG = "DDMNativeEngine";
+ static {
+ try {//load jni_dualcamera
+ System.loadLibrary("jni_dualcamera");
+ mLibLoaded = true;
+ Log.v(TAG, "successfully loaded jni_dualcamera lib");
+ } catch (UnsatisfiedLinkError e) {
+ Log.e(TAG, "failed to load jni_dualcamera lib");
+ Log.e(TAG, e.toString());
+ e.printStackTrace();
+ mLibLoaded = false;
+ }
+
+ }
+
+ private CaptureResult.Key<byte[]> SCALE_CROP_ROTATION_REPROCESS_BLOB =
+ new CaptureResult.Key<byte[]>(
+ "org.codeaurora.qcamera3.hal_private_data.reprocess_data_blob",
+ byte[].class);
+
+ private static boolean mLibLoaded;
+ private Image mBayerImage;
+ private Image mMonoImage;
+ private ByteBuffer mPrimaryY;
+ private ByteBuffer mPrivaryVU;
+ CamReprocessInfo mBayerCamReprocessInfo;
+ CamReprocessInfo mMonoCamReprocessInfo;
+ CamSystemCalibrationData mCamSystemCalibrationData;
+ private float mLensFocusDistance;
+ private static final int Y_PLANE = 0;
+ private static final int VU_PLANE = 2;
+
+ public boolean getDepthMapSize(int[] depthMap){
+ return nativeGetDepthMapSize(mBayerImage.getWidth(), mBayerImage.getHeight(), depthMap);
+ }
+
+ public void setCamSystemCalibrationData(CamSystemCalibrationData otpCalibration){
+ mCamSystemCalibrationData = otpCalibration;
+ }
+
+ public String getOTPCalibration() {
+ return mCamSystemCalibrationData.toString();
+ }
+
+ public void reset() {
+ mBayerImage = null;
+ mMonoImage = null;
+ mBayerCamReprocessInfo = null;
+ mMonoCamReprocessInfo = null;
+ mLensFocusDistance = 0;
+ }
+ public boolean isReadyForGenerateDepth(){
+ return mBayerImage != null && mMonoImage != null
+ && mBayerCamReprocessInfo != null && mMonoCamReprocessInfo != null;
+ }
+
+ public void setBayerLensFocusDistance(float lensFocusDistance) {
+ mLensFocusDistance = lensFocusDistance;
+ }
+ public void setBayerImage(Image image){
+ mBayerImage = image;
+ }
+
+ public void setMonoImage(Image image) {
+ mMonoImage = image;
+ }
+
+ public void setBayerReprocessResult(CaptureResult result ){
+ byte[] bytes = result.get(SCALE_CROP_ROTATION_REPROCESS_BLOB);
+ mBayerCamReprocessInfo = CamReprocessInfo.createCamReprocessFromBytes(bytes);
+ }
+
+ public String getBayerScaleCrop() {
+ return mBayerCamReprocessInfo.toString();
+ }
+
+ public void setMonoReprocessResult(CaptureResult result) {
+ byte[] bytes = result.get(SCALE_CROP_ROTATION_REPROCESS_BLOB);
+ mMonoCamReprocessInfo = CamReprocessInfo.createCamReprocessFromBytes(bytes);
+ }
+
+ public String getMonoScaleCrop(){
+ return mMonoCamReprocessInfo.toString();
+ }
+
+ public boolean dualCameraGenerateDDM(byte[] depthMapBuffer, int depthMapStride, Rect roiRect) {
+ if ( mLensFocusDistance == 0 ){
+ Log.e(TAG, " dualCameraGenerateDDM error: mLensFocusDistance is 0");
+ return false;
+ }
+
+ if (mBayerImage == null || mMonoImage == null ) {
+ Log.e(TAG, "mBayerImage=" +(mBayerImage == null)+ " mMonoImage=" + (mMonoImage == null));
+ return false;
+ }
+
+ if ( depthMapBuffer == null ) {
+ Log.e(TAG, "depthMapBuffer can't be null");
+ return false;
+ }
+
+ if ( mMonoCamReprocessInfo== null
+ || mBayerCamReprocessInfo == null
+ || mCamSystemCalibrationData == null ) {
+ Log.e(TAG, "mMonoCamReprocessInfo== null:" +(mMonoCamReprocessInfo== null)
+ + " mBayerCamReprocessInfo == null:" +(mBayerCamReprocessInfo == null)
+ + " mCamSystemCalibrationData == null:" +(mCamSystemCalibrationData == null));
+ return false;
+ }
+
+ Plane[] bayerPlanes = mBayerImage.getPlanes();
+ Plane[] monoPlanes = mMonoImage.getPlanes();
+ int[] goodRoi = new int[4];
+ boolean result = nativeDualCameraGenerateDDM(
+ bayerPlanes[Y_PLANE].getBuffer(),
+ bayerPlanes[VU_PLANE].getBuffer(),
+ mBayerImage.getWidth(),
+ mBayerImage.getHeight(),
+ bayerPlanes[Y_PLANE].getRowStride(),
+ bayerPlanes[VU_PLANE].getRowStride(),
+
+ monoPlanes[Y_PLANE].getBuffer(),
+ monoPlanes[VU_PLANE].getBuffer(),
+ mMonoImage.getWidth(),
+ mMonoImage.getHeight(),
+ monoPlanes[Y_PLANE].getRowStride(),
+ monoPlanes[VU_PLANE].getRowStride(),
+
+ depthMapBuffer,
+ depthMapStride,
+
+ goodRoi,
+
+ mBayerCamReprocessInfo.toString(),
+ mMonoCamReprocessInfo.toString(),
+ mCamSystemCalibrationData.toString(),
+ mLensFocusDistance,
+ true);
+ roiRect.left = goodRoi[0];
+ roiRect.top = goodRoi[1];
+ roiRect.right = goodRoi[0] + goodRoi[2];
+ roiRect.bottom = goodRoi[1] + goodRoi[3];
+
+ return result;
+ }
+
+
+
+ private native boolean nativeGetDepthMapSize(int primaryWidth, int primaryHeight,int[] size);
+
+ private native boolean nativeDualCameraGenerateDDM(
+ ByteBuffer primaryY,
+ ByteBuffer primaryVU,
+ int primaryWidth,
+ int primaryHeight,
+ int primaryStrideY,
+ int primaryStrideVU,
+
+ ByteBuffer auxiliaryY,
+ ByteBuffer auxiliaryVU,
+ int auxiliaryWidth,
+ int auxiliaryHeight,
+ int auxiliaryStrideY,
+ int auxiliaryStrideVU,
+
+ byte[] outDst,
+ int dstStride,
+
+ int[] roiRect,
+
+ String scaleCropRotationDataPrimaryCamera,
+ String scaleCropRotationDataAuxiliaryCamera,
+ String otpCalibration,
+ float focalLengthPrimaryCamera,
+ boolean isAuxiliaryMonoSensor);
+
+ public static class DepthMap{
+ private int width;
+ private int height;
+ private ByteBuffer buffer;
+ private int stride;
+ private Rect roi;
+ }
+ public static class CamStreamCropInfo{
+ int stream_id;
+ Rect crop;
+ Rect roi_map;
+
+ private CamStreamCropInfo(){}
+
+ public static CamStreamCropInfo createFromBytes(byte[] bytes) {
+ ByteBuffer buffer = ByteBuffer.wrap(bytes);
+ buffer.order(ByteOrder.LITTLE_ENDIAN);
+ return createFromByteBuffer(buffer);
+ }
+
+ public static CamStreamCropInfo createFromByteBuffer(ByteBuffer buffer) {
+ CamStreamCropInfo camStreamCropInfo = new CamStreamCropInfo();
+ camStreamCropInfo.stream_id = buffer.getInt();
+ Rect crop = new Rect();
+ crop.left = buffer.getInt();
+ crop.top = buffer.getInt();
+ crop.right = crop.left + buffer.getInt();
+ crop.bottom = crop.top + buffer.getInt();
+ camStreamCropInfo.crop = crop;
+
+ Rect roi_map = new Rect();
+ roi_map.left = buffer.getInt();
+ roi_map.top = buffer.getInt();
+ roi_map.right = roi_map.left + buffer.getInt();
+ roi_map.bottom = roi_map.top + buffer.getInt();
+ camStreamCropInfo.roi_map = roi_map;
+
+ return camStreamCropInfo;
+ }
+ }
+
+ public static class CamRotationInfo {
+ int jpeg_rotation;
+ int device_rotation;
+ int stream_id;
+ private CamRotationInfo(){}
+
+ public static CamRotationInfo createCamReprocessFromBytes(byte[] bytes) {
+ ByteBuffer buf = ByteBuffer.wrap(bytes);
+ buf.order(ByteOrder.LITTLE_ENDIAN);
+ return createFromByteBuffer(buf);
+ }
+ public static CamRotationInfo createFromByteBuffer(ByteBuffer buffer) {
+ CamRotationInfo rotation_info = new CamRotationInfo();
+ rotation_info.jpeg_rotation = buffer.getInt();
+ rotation_info.device_rotation = buffer.getInt();
+ rotation_info.stream_id = buffer.getInt();
+ return rotation_info;
+ }
+ }
+ public static class CamReprocessInfo{
+ CamStreamCropInfo sensor_crop_info;
+ CamStreamCropInfo camif_crop_info;
+ CamStreamCropInfo isp_crop_info;
+ CamStreamCropInfo cpp_crop_info;
+ float af_focal_length_ratio;
+ int pipeline_flip;
+ CamRotationInfo rotation_info;
+
+ private final String SCALE_CROP_ROTATION_FORMAT_STRING[] = {
+ "Sensor Crop left = %d\n",
+ "Sensor Crop top = %d\n",
+ "Sensor Crop width = %d\n",
+ "Sensor Crop height = %d\n",
+ "Sensor ROI Map left = %d\n",
+ "Sensor ROI Map top = %d\n",
+ "Sensor ROI Map width = %d\n",
+ "Sensor ROI Map height = %d\n",
+ "CAMIF Crop left = %d\n",
+ "CAMIF Crop top = %d\n",
+ "CAMIF Crop width = %d\n",
+ "CAMIF Crop height = %d\n",
+ "CAMIF ROI Map left = %d\n",
+ "CAMIF ROI Map top = %d\n",
+ "CAMIF ROI Map width = %d\n",
+ "CAMIF ROI Map height = %d\n",
+ "ISP Crop left = %d\n",
+ "ISP Crop top = %d\n",
+ "ISP Crop width = %d\n",
+ "ISP Crop height = %d\n",
+ "ISP ROI Map left = %d\n",
+ "ISP ROI Map top = %d\n",
+ "ISP ROI Map width = %d\n",
+ "ISP ROI Map height = %d\n",
+ "CPP Crop left = %d\n",
+ "CPP Crop top = %d\n",
+ "CPP Crop width = %d\n",
+ "CPP Crop height = %d\n",
+ "CPP ROI Map left = %d\n",
+ "CPP ROI Map top = %d\n",
+ "CPP ROI Map width = %d\n",
+ "CPP ROI Map height = %d\n",
+ "Focal length Ratio = %f\n",
+ "Current pipeline mirror flip setting = %d\n",
+ "Current pipeline rotation setting = %d\n"
+ };
+
+ public static CamReprocessInfo createCamReprocessFromBytes(byte[] bytes){
+ ByteBuffer buf = ByteBuffer.wrap(bytes);
+ buf.order(ByteOrder.LITTLE_ENDIAN);
+ return createCamReprocessFromBytes(buf);
+ }
+ public static CamReprocessInfo createCamReprocessFromBytes(ByteBuffer buffer){
+ CamReprocessInfo scaleCropRotation = new CamReprocessInfo();
+ scaleCropRotation.sensor_crop_info = CamStreamCropInfo.createFromByteBuffer(buffer);
+ scaleCropRotation.camif_crop_info = CamStreamCropInfo.createFromByteBuffer(buffer);
+ scaleCropRotation.isp_crop_info = CamStreamCropInfo.createFromByteBuffer(buffer);
+ scaleCropRotation.cpp_crop_info = CamStreamCropInfo.createFromByteBuffer(buffer);
+ scaleCropRotation.af_focal_length_ratio = buffer.getFloat();
+ scaleCropRotation.pipeline_flip = buffer.getInt();
+ scaleCropRotation.rotation_info = CamRotationInfo.createFromByteBuffer(buffer);
+ return scaleCropRotation;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append(String.format(SCALE_CROP_ROTATION_FORMAT_STRING[0], this.sensor_crop_info.crop.left));
+ sb.append(String.format(SCALE_CROP_ROTATION_FORMAT_STRING[1], this.sensor_crop_info.crop.top));
+ sb.append(String.format(SCALE_CROP_ROTATION_FORMAT_STRING[2], this.sensor_crop_info.crop.width()));
+ sb.append(String.format(SCALE_CROP_ROTATION_FORMAT_STRING[3], this.sensor_crop_info.crop.height()));
+ sb.append(String.format(SCALE_CROP_ROTATION_FORMAT_STRING[4], this.sensor_crop_info.roi_map.left));
+ sb.append(String.format(SCALE_CROP_ROTATION_FORMAT_STRING[5], this.sensor_crop_info.roi_map.top));
+ sb.append(String.format(SCALE_CROP_ROTATION_FORMAT_STRING[6], this.sensor_crop_info.roi_map.width()));
+ sb.append(String.format(SCALE_CROP_ROTATION_FORMAT_STRING[7], this.sensor_crop_info.roi_map.height()));
+
+ sb.append(String.format(SCALE_CROP_ROTATION_FORMAT_STRING[8], this.camif_crop_info.crop.left));
+ sb.append(String.format(SCALE_CROP_ROTATION_FORMAT_STRING[9], this.camif_crop_info.crop.top));
+ sb.append(String.format(SCALE_CROP_ROTATION_FORMAT_STRING[10], this.camif_crop_info.crop.width()));
+ sb.append(String.format(SCALE_CROP_ROTATION_FORMAT_STRING[11], this.camif_crop_info.crop.height()));
+ sb.append(String.format(SCALE_CROP_ROTATION_FORMAT_STRING[12], this.camif_crop_info.roi_map.left));
+ sb.append(String.format(SCALE_CROP_ROTATION_FORMAT_STRING[13], this.camif_crop_info.roi_map.top));
+ sb.append(String.format(SCALE_CROP_ROTATION_FORMAT_STRING[14], this.camif_crop_info.roi_map.width()));
+ sb.append(String.format(SCALE_CROP_ROTATION_FORMAT_STRING[15], this.camif_crop_info.roi_map.height()));
+
+ sb.append(String.format(SCALE_CROP_ROTATION_FORMAT_STRING[16], this.isp_crop_info.crop.left));
+ sb.append(String.format(SCALE_CROP_ROTATION_FORMAT_STRING[17], this.isp_crop_info.crop.top));
+ sb.append(String.format(SCALE_CROP_ROTATION_FORMAT_STRING[18], this.isp_crop_info.crop.width()));
+ sb.append(String.format(SCALE_CROP_ROTATION_FORMAT_STRING[19], this.isp_crop_info.crop.height()));
+ sb.append(String.format(SCALE_CROP_ROTATION_FORMAT_STRING[20], this.isp_crop_info.roi_map.left));
+ sb.append(String.format(SCALE_CROP_ROTATION_FORMAT_STRING[21], this.isp_crop_info.roi_map.top));
+ sb.append(String.format(SCALE_CROP_ROTATION_FORMAT_STRING[22], this.isp_crop_info.roi_map.width()));
+ sb.append(String.format(SCALE_CROP_ROTATION_FORMAT_STRING[23], this.isp_crop_info.roi_map.height()));
+
+ sb.append(String.format(SCALE_CROP_ROTATION_FORMAT_STRING[24], this.cpp_crop_info.crop.left));
+ sb.append(String.format(SCALE_CROP_ROTATION_FORMAT_STRING[25], this.cpp_crop_info.crop.top));
+ sb.append(String.format(SCALE_CROP_ROTATION_FORMAT_STRING[26], this.cpp_crop_info.crop.width()));
+ sb.append(String.format(SCALE_CROP_ROTATION_FORMAT_STRING[27], this.cpp_crop_info.crop.height()));
+ sb.append(String.format(SCALE_CROP_ROTATION_FORMAT_STRING[28], this.cpp_crop_info.roi_map.left));
+ sb.append(String.format(SCALE_CROP_ROTATION_FORMAT_STRING[29], this.cpp_crop_info.roi_map.top));
+ sb.append(String.format(SCALE_CROP_ROTATION_FORMAT_STRING[30], this.cpp_crop_info.roi_map.width()));
+ sb.append(String.format(SCALE_CROP_ROTATION_FORMAT_STRING[31], this.cpp_crop_info.roi_map.height()));
+
+ sb.append(String.format(SCALE_CROP_ROTATION_FORMAT_STRING[32], this.af_focal_length_ratio));
+
+ sb.append(String.format(SCALE_CROP_ROTATION_FORMAT_STRING[33], this.pipeline_flip));
+
+ sb.append(String.format(SCALE_CROP_ROTATION_FORMAT_STRING[34], this.rotation_info.jpeg_rotation));
+ return sb.toString();
+ }
+
+ }
+
+
+} \ No newline at end of file
diff --git a/src/org/codeaurora/snapcam/filter/GDepth.java b/src/org/codeaurora/snapcam/filter/GDepth.java
new file mode 100644
index 000000000..8f9a935a9
--- /dev/null
+++ b/src/org/codeaurora/snapcam/filter/GDepth.java
@@ -0,0 +1,307 @@
+/*
+ * Copyright (c) 2017, 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 org.codeaurora.snapcam.filter;
+
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.Rect;
+import android.hardware.Camera.Size;
+import android.util.Base64;
+import android.util.Log;
+
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.nio.ByteBuffer;
+
+import java.io.OutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.BufferedOutputStream;
+
+import com.adobe.xmp.XMPException;
+import com.adobe.xmp.XMPMeta;
+import com.adobe.xmp.XMPMetaFactory;
+
+public class GDepth{
+ private final static String TAG = "Flow_GDepth";
+ public final static String NAMESPACE_URL = "http://ns.google.com/photos/1.0/depthmap/";
+ public final static String PREFIX = "GDepth";
+ public final static String PROPERTY_FORMAT = "Format";
+ public final static String PROPERTY_NEAR = "Near";
+ public final static String PROPERTY_FAR = "Far";
+ public final static String PROPERTY_MIME = "Mime";
+ public final static String PROPERTY_DATA = "Data";
+ //extend roi
+ public final static String PROPERTY_ROI_X = "RoiX";
+ public final static String PROPERTY_ROI_Y = "RoiY";
+ public final static String PROPERTY_ROI_WIDTH = "RoiWidth";
+ public final static String PROPERTY_ROI_HEIGHT = "RoiHeight";
+
+ public final static String FORMAT_RANGE_INVERSE="RangeInverse";
+ public final static String FORMAT_RANGLE_LINEAR = "RangeLinear";
+ private final static String MIME = "image/jpeg";
+
+ private DepthMap mDepthMap;
+ private String mData;
+ private int mNear;
+ private int mFar;
+ private final String mFormat = "RangeLinear";
+ private int[] mMap;
+
+ static {
+ try {
+ XMPMetaFactory.getSchemaRegistry().registerNamespace(
+ NAMESPACE_URL, PREFIX);
+ } catch (XMPException e) {
+ e.printStackTrace();
+ }
+ }
+
+ private GDepth(DepthMap depthMap){
+ mDepthMap = depthMap;
+ mMap = new int[depthMap.buffer.length];
+
+ for( int i=0; i < mMap.length; ++i ) {
+ mMap[i] = (256+depthMap.buffer[i])%256;
+ }
+ mNear = mFar = mMap[0];
+ for(int d : mMap ) {
+ if ( d < mNear) {
+ mNear = d;
+ }else if ( d > mFar) {
+ mFar = d;
+ }
+ }
+ }
+
+ public int getNear() {
+ return mNear;
+ }
+
+ public int getFar(){
+ return mFar;
+ }
+
+ public String getFormat(){
+ return mFormat;
+ }
+
+ public String getMime() {
+ return MIME;
+ }
+
+ public String getData(){
+ return mData;
+ }
+
+ public Rect getRoi() {
+ return mDepthMap.roi;
+ }
+ public static GDepth createGDepth(DepthMap depthMap){
+ GDepth gDepth = new GDepth(depthMap);
+ if ( gDepth.encoding() ) {
+ return gDepth;
+ }
+ return null;
+ }
+
+ private boolean encoding(){
+ Log.d(TAG, "encoding");
+ boolean result = false;
+ int[] grayscaleImage = convertIntoImage(mMap);
+ byte[] jpegBytes = compressToJPEG(grayscaleImage );
+ if (jpegBytes != null ) {
+ String base64String = serializeAsBase64Str(jpegBytes);
+ result = true;
+ mData = base64String;
+ }else{
+ Log.e(TAG, "compressToJPEG failure");
+ }
+
+ return result;
+ }
+
+ private int[] convertIntoImage(int[] depthMap) {
+ int[] imageBuffer = new int[depthMap.length];
+ float dividend = mFar-mNear;
+ for ( int i =0; i < imageBuffer.length; ++i) {
+ if ( depthMap[i] == 0 && mNear == 0 ) {
+ imageBuffer[i] = 0;
+ }else{
+ imageBuffer[i] = getRangeLinearDepth(depthMap[i], mNear, dividend);
+ }
+ }
+ return imageBuffer;
+ }
+
+ private int getRangeLinearDepth(int depth, int near, float dividend) {
+ return (int)(255*(depth-near)/dividend);
+ }
+
+ private int getRangeLinearDepth(int depth, int near, int far) {
+ return (int)(255*(depth-near)/(float)(far-near));
+ }
+
+ private byte[] compressToJPEG(int[] image) {
+ Log.d(TAG, "compressToJPEG int[].size=" + image.length);
+ byte[] bitsBuffer = new byte[image.length];
+ for(int i=0; i < image.length; ++i){
+ bitsBuffer[i] = (byte)image[i];
+ }
+ return compressToJPEG(bitsBuffer);
+ }
+
+ private byte[] compressToJPEG(byte[] image) {
+ Log.d(TAG, "compressToJPEG byte[].size=" + image.length);
+ Bitmap bmp = BitmapFactory.decodeByteArray (image, 0, image.length);
+ if ( bmp == null ) {
+ Log.d(TAG, " buffer can't be decoded ");
+ return null;
+ }
+ ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+ bmp.compress(Bitmap.CompressFormat.JPEG, 100, outputStream);
+ return outputStream.toByteArray();
+ }
+
+ private String serializeAsBase64Str(byte[] image) {
+ Log.d(TAG, "serializeAsBase64Str");
+ return Base64.encodeToString(image, Base64.DEFAULT);
+ }
+
+ private void saveAsFile(String str, String name){
+ Log.d(TAG, "saveAsFile " + "sdcard/DDM/"+ TAG + name + ".log");
+ File file = new File("sdcard/DDM/"+ TAG + name + ".log");
+
+ OutputStream out = null;
+ byte[] bytes = str.getBytes();
+ try {
+ out = new BufferedOutputStream(new FileOutputStream(file));
+ out.write(bytes, 0, bytes.length);
+ }catch(Exception e) {
+ Log.d(TAG, e.toString());
+ }finally {
+ if (out != null) {
+ try {
+ out.close();
+ }catch(Exception e){
+ Log.d(TAG, e.toString());
+ }
+ }
+ }
+ }
+
+ private void saveAsJPEG(byte[] bytes){
+ Log.d(TAG, "saveAsJPEG");
+ File file = new File("sdcard/"+ System.currentTimeMillis() + "_depth.JPEG");
+ OutputStream out = null;
+ try {
+ out = new BufferedOutputStream(new FileOutputStream(file));
+ out.write(bytes, 0, bytes.length);
+ }catch(Exception e) {
+ Log.d(TAG, e.toString());
+ }finally {
+ if (out != null) {
+ try {
+ out.close();
+ }catch(Exception e){
+ Log.d(TAG, e.toString());
+ }
+ }
+ }
+ }
+
+ public static class DepthMap{
+ public byte[] buffer;
+ public int width;
+ public int height;
+ public Rect roi;
+ public byte[] rawDepth;
+ public DepthMap(int width, int height){
+ this.width = width;
+ this.height = height;
+ }
+ }
+
+
+ private GDepth(int near, int far, String data) {
+ this.mNear = near;
+ this.mFar = far;
+ this.mData = data;
+ }
+ public static GDepth createGDepth(XMPMeta xmpMeta){
+ try {
+ int near = Integer.parseInt((String)
+ xmpMeta.getProperty(GDepth.NAMESPACE_URL, PROPERTY_NEAR).getValue());
+ int far = Integer.parseInt((String)
+ xmpMeta.getProperty(GDepth.NAMESPACE_URL, PROPERTY_FAR).getValue());
+ String data = (String)xmpMeta.getProperty(
+ GDepth.NAMESPACE_URL, PROPERTY_DATA).getValue();
+ String format = (String)xmpMeta.getProperty(
+ GDepth.NAMESPACE_URL, PROPERTY_FORMAT).getValue();
+ Log.d(TAG, "new GDepth: nerar=" + near+ " far=" + far + "format=" + format+ " data=" + data);
+ int x = Integer.parseInt((String)
+ xmpMeta.getProperty(GDepth.NAMESPACE_URL, PROPERTY_ROI_X).getValue());
+ int y = Integer.parseInt((String)
+ xmpMeta.getProperty(GDepth.NAMESPACE_URL, PROPERTY_ROI_Y).getValue());
+ int width = Integer.parseInt((String)
+ xmpMeta.getProperty(GDepth.NAMESPACE_URL, PROPERTY_ROI_WIDTH).getValue());
+ int height = Integer.parseInt((String)
+ xmpMeta.getProperty(GDepth.NAMESPACE_URL, PROPERTY_ROI_HEIGHT).getValue());
+ Log.d(TAG, "x=" + x + " y=" + y + " width=" + width + " height=" + height);
+ GDepth gDepth = new GDepth(near, far, data);
+ return gDepth;
+ }catch(XMPException e){
+ Log.e(TAG, e.toString());
+ }catch(Exception e) {
+ Log.e(TAG, e.toString());
+ }
+ return null;
+ }
+
+ public boolean decode() {
+ Log.d(TAG, "decode");
+ byte[] depthBuffer = Base64.decode(mData, Base64.DEFAULT);
+ saveAsJPEG(depthBuffer);
+ //TODO:
+ //convert JPEG compress bytes to bytes
+
+ int[] intDepthBuffer = new int[depthBuffer.length];
+ int[] intDepth = new int[depthBuffer.length];
+
+ //conver to 0-255;
+ for( int i=0; i < intDepthBuffer.length; ++i) {
+ intDepthBuffer[i] = (256+depthBuffer[i])%256;
+ }
+ //conver to depth value
+
+ return false;
+
+ }
+} \ No newline at end of file
diff --git a/src/org/codeaurora/snapcam/filter/GImage.java b/src/org/codeaurora/snapcam/filter/GImage.java
new file mode 100644
index 000000000..bac6fd296
--- /dev/null
+++ b/src/org/codeaurora/snapcam/filter/GImage.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2017, 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 org.codeaurora.snapcam.filter;
+
+import com.adobe.xmp.XMPException;
+import com.adobe.xmp.XMPMeta;
+import com.adobe.xmp.XMPMetaFactory;
+
+import android.util.Base64;
+
+public class GImage{
+ public final static String NAMESPACE_URL = "http://ns.google.com/photos/1.0/image/";
+ public final static String PREFIX = "GImage";
+ public final static String PROPERTY_MIME = "Mime";
+ public final static String PROPERTY_DATA = "Data";
+
+ static {
+ try {
+ XMPMetaFactory.getSchemaRegistry().registerNamespace(
+ NAMESPACE_URL, PREFIX);
+ } catch (XMPException e) {
+ e.printStackTrace();
+ }
+ }
+
+ private String mMime = "image/jpeg";
+ private String mData;
+
+ public GImage(byte[] data, String mime){
+ mData = Base64.encodeToString(data, Base64.DEFAULT);
+ mMime = mime;
+ }
+
+ public String getMime(){
+ return mMime;
+ }
+
+ public String getData(){
+ return mData;
+ }
+} \ No newline at end of file