From d72bad4bf46a1cbc49ff1685aac8a3c58c4d7546 Mon Sep 17 00:00:00 2001 From: weijiew Date: Thu, 16 Feb 2017 11:20:37 +0800 Subject: SnapdragonCamera: FR40621 ClearSight/DDM integrate ClearSight/DDM, integrate Clear Sight in Camera Framework CRs-Fixed: 1108837 Change-Id: Ibde73b15c9361294eb2e0e05967763005a4546e0 --- .../snapcam/filter/ClearSightImageProcessor.java | 329 ++++++++++++++--- .../snapcam/filter/ClearSightNativeEngine.java | 4 +- .../codeaurora/snapcam/filter/DDMNativeEngine.java | 396 +++++++++++++++++++++ src/org/codeaurora/snapcam/filter/GDepth.java | 307 ++++++++++++++++ src/org/codeaurora/snapcam/filter/GImage.java | 68 ++++ 5 files changed, 1060 insertions(+), 44 deletions(-) mode change 100755 => 100644 src/org/codeaurora/snapcam/filter/ClearSightImageProcessor.java create mode 100644 src/org/codeaurora/snapcam/filter/DDMNativeEngine.java create mode 100644 src/org/codeaurora/snapcam/filter/GDepth.java create mode 100644 src/org/codeaurora/snapcam/filter/GImage.java (limited to 'src/org/codeaurora/snapcam/filter') diff --git a/src/org/codeaurora/snapcam/filter/ClearSightImageProcessor.java b/src/org/codeaurora/snapcam/filter/ClearSightImageProcessor.java old mode 100755 new mode 100644 index bfd58db28..8a6e7667f --- 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.camera.cs.threshold"; @@ -87,6 +95,7 @@ public class ClearSightImageProcessor { private static final String PERSIST_DUMP_FRAMES_KEY = "persist.camera.cs.dumpframes"; private static final String PERSIST_DUMP_YUV_KEY = "persist.camera.cs.dumpyuv"; private static final String PERSIST_CS_TIMEOUT_KEY = "persist.camera.cs.timeout"; + private static final String PERSIST_DUMP_DEPTH_KEY = "persist.camera.cs.dumpdepth"; private static final long DEFAULT_TIMESTAMP_THRESHOLD_MS = 10; private static final int DEFAULT_IMAGES_TO_BURST = 4; @@ -106,6 +115,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 +127,10 @@ public class ClearSightImageProcessor { new CameraCharacteristics.Key<>( "org.codeaurora.qcamera3.dualcam_calib_meta_data.dualcam_calib_meta_data_blob", byte[].class); + private CaptureResult.Key SCALE_CROP_ROTATION_REPROCESS_BLOB = + new CaptureResult.Key( + "org.codeaurora.qcamera3.hal_private_data.reprocess_data_blob", + byte[].class); private NamedImages mNamedImages; private ImageReader[] mImageReader = new ImageReader[NUM_CAM]; @@ -128,10 +144,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 +163,7 @@ public class ClearSightImageProcessor { private int mCsTimeout; private boolean mDumpImages; private boolean mDumpYUV; + private boolean mDumpDepth; private boolean mIsClosing; private int mFinishReprocessNum; @@ -167,8 +187,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 +221,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 +246,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 +311,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 SCALE_CROP_ROTATION_REPROCESS_BLOB = + new CaptureResult.Key( + "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 -- cgit v1.2.3