summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinux Build Service Account <lnxbuild@localhost>2018-03-08 08:40:36 -0800
committerGerrit - the friendly Code Review server <code-review@localhost>2018-03-08 08:40:36 -0800
commita06814aafd8a3dc6336ef24df9a12fcb6d585500 (patch)
tree1ea31d3f222871c314b4db25123219d83d7f82bb
parent7d7f377f7bafbec1999e3addf8f607616f957132 (diff)
parentcfdc874eb6e23e101bd32d10183e419894e405f2 (diff)
downloadandroid_packages_apps_Snap-a06814aafd8a3dc6336ef24df9a12fcb6d585500.tar.gz
android_packages_apps_Snap-a06814aafd8a3dc6336ef24df9a12fcb6d585500.tar.bz2
android_packages_apps_Snap-a06814aafd8a3dc6336ef24df9a12fcb6d585500.zip
Merge "SnapdragonCamera:DeepPortrait"
-rwxr-xr-x[-rw-r--r--]Android.mk2
-rwxr-xr-xres/drawable-hdpi/deep_portrait.pngbin0 -> 2198 bytes
-rwxr-xr-xres/drawable-hdpi/deep_portrait_black.pngbin0 -> 3400 bytes
-rwxr-xr-xres/drawable-hdpi/deep_portrait_on.pngbin0 -> 2859 bytes
-rwxr-xr-xres/drawable-mdpi/deep_portrait.pngbin0 -> 1060 bytes
-rwxr-xr-xres/drawable-mdpi/deep_portrait_black.pngbin0 -> 2471 bytes
-rwxr-xr-xres/drawable-mdpi/deep_portrait_on.pngbin0 -> 2135 bytes
-rwxr-xr-xres/layout/capture_module.xml9
-rw-r--r--res/layout/one_ui_layout.xml17
-rwxr-xr-xres/values/camera2arrays.xml11
-rwxr-xr-xres/values/qcomstrings.xml6
-rwxr-xr-xsrc/com/android/camera/CaptureModule.java126
-rwxr-xr-xsrc/com/android/camera/CaptureUI.java118
-rwxr-xr-xsrc/com/android/camera/SettingsManager.java24
-rwxr-xr-xsrc/com/android/camera/deepportrait/CamGLRenderObserver.java40
-rwxr-xr-xsrc/com/android/camera/deepportrait/CamGLRenderer.java695
-rwxr-xr-xsrc/com/android/camera/deepportrait/CamRenderShader.java105
-rwxr-xr-xsrc/com/android/camera/deepportrait/CamRenderTexture.java114
-rwxr-xr-xsrc/com/android/camera/deepportrait/DPImage.java57
-rwxr-xr-xsrc/com/android/camera/deepportrait/GLCameraPreview.java343
-rwxr-xr-xsrc/com/android/camera/imageprocessor/FrameProcessor.java52
-rwxr-xr-x[-rw-r--r--]src/com/android/camera/imageprocessor/PostProcessor.java115
-rwxr-xr-xsrc/com/android/camera/imageprocessor/filter/DeepPortraitFilter.java325
-rwxr-xr-xsrc/com/android/camera/ui/OneUICameraControls.java14
24 files changed, 2130 insertions, 43 deletions
diff --git a/Android.mk b/Android.mk
index d6d543157..186f19672 100644..100755
--- a/Android.mk
+++ b/Android.mk
@@ -27,6 +27,7 @@ LOCAL_PRIVILEGED_MODULE := true
#LOCAL_SDK_VERSION := current
LOCAL_RENDERSCRIPT_TARGET_API := 23
+LOCAL_MULTILIB := 32
#LOCAL_OVERRIDES_PACKAGES := Camera2
@@ -37,6 +38,7 @@ LOCAL_MULTILIB := 32
# If this is an unbundled build (to install separately) then include
# the libraries in the APK, otherwise just put them in /system/lib and
# leave them out of the APK
+
#ifneq (,$(TARGET_BUILD_APPS))
LOCAL_JNI_SHARED_LIBRARIES := libjni_snapcammosaic libjni_snapcamtinyplanet libjni_imageutil
#else
diff --git a/res/drawable-hdpi/deep_portrait.png b/res/drawable-hdpi/deep_portrait.png
new file mode 100755
index 000000000..67853ef2c
--- /dev/null
+++ b/res/drawable-hdpi/deep_portrait.png
Binary files differ
diff --git a/res/drawable-hdpi/deep_portrait_black.png b/res/drawable-hdpi/deep_portrait_black.png
new file mode 100755
index 000000000..c47a92e33
--- /dev/null
+++ b/res/drawable-hdpi/deep_portrait_black.png
Binary files differ
diff --git a/res/drawable-hdpi/deep_portrait_on.png b/res/drawable-hdpi/deep_portrait_on.png
new file mode 100755
index 000000000..18cf7774a
--- /dev/null
+++ b/res/drawable-hdpi/deep_portrait_on.png
Binary files differ
diff --git a/res/drawable-mdpi/deep_portrait.png b/res/drawable-mdpi/deep_portrait.png
new file mode 100755
index 000000000..bfe7cb8ac
--- /dev/null
+++ b/res/drawable-mdpi/deep_portrait.png
Binary files differ
diff --git a/res/drawable-mdpi/deep_portrait_black.png b/res/drawable-mdpi/deep_portrait_black.png
new file mode 100755
index 000000000..d0d5f0c50
--- /dev/null
+++ b/res/drawable-mdpi/deep_portrait_black.png
Binary files differ
diff --git a/res/drawable-mdpi/deep_portrait_on.png b/res/drawable-mdpi/deep_portrait_on.png
new file mode 100755
index 000000000..87d241608
--- /dev/null
+++ b/res/drawable-mdpi/deep_portrait_on.png
Binary files differ
diff --git a/res/layout/capture_module.xml b/res/layout/capture_module.xml
index b3ade9f55..a9c8f88e5 100755
--- a/res/layout/capture_module.xml
+++ b/res/layout/capture_module.xml
@@ -32,6 +32,7 @@
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
+ android:id="@+id/mdp_preivew_frame"
android:layout_gravity="center_vertical|center_horizontal">
<com.android.camera.ui.AutoFitSurfaceView
android:id="@+id/mdp_preview_content"
@@ -41,10 +42,16 @@
<com.android.camera.ui.AutoFitSurfaceView
android:layout_width="300dp"
android:layout_height="300dp"
- android:id="@+id/mdp_preview_content_mono"
+ android:id="@+id/mdp_preview_content_mono"
android:visibility="gone"/>
</FrameLayout>
+ <FrameLayout
+ android:id="@+id/camera_glpreview"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_gravity="center_vertical|center_horizontal" />
+
<View
android:id="@+id/preview_cover"
android:layout_width="match_parent"
diff --git a/res/layout/one_ui_layout.xml b/res/layout/one_ui_layout.xml
index 59e31b95d..61c55cd3a 100644
--- a/res/layout/one_ui_layout.xml
+++ b/res/layout/one_ui_layout.xml
@@ -132,6 +132,10 @@
android:id="@+id/ts_makeup_switcher"
style="@style/OneUIMenuButton" />
+ <com.android.camera.ui.RotateImageView
+ android:id="@+id/deepportrait_switcher"
+ style="@style/OneUIMenuButton" />
+
<LinearLayout
android:id="@+id/remaining_photos"
android:layout_width="wrap_content"
@@ -164,6 +168,19 @@
android:layout_width="20dp"
android:src="@drawable/icon_x" />
+
+ <SeekBar
+ android:layout_width="320dp"
+ android:layout_height="40dp"
+ android:maxHeight="3dip"
+ android:minHeight="1dip"
+ android:visibility="gone"
+ android:layout_gravity="center_horizontal|bottom"
+ android:layout_marginBottom="90dp"
+ android:progressDrawable="@drawable/beautify_progressbar_style"
+ android:thumb="@drawable/ic_beautify_oval"
+ android:id="@+id/deepportrait_seekbar"/>
+
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
diff --git a/res/values/camera2arrays.xml b/res/values/camera2arrays.xml
index 8723ecd66..80a0151b4 100755
--- a/res/values/camera2arrays.xml
+++ b/res/values/camera2arrays.xml
@@ -159,6 +159,7 @@
<item>104</item>
<item>109</item>
<item>110</item>
+ <item>111</item>
</string-array>
<!-- Camera Preferences Scene Mode dialog box entries -->
@@ -187,6 +188,7 @@
<item>@string/pref_camera_scenemode_entry_panorama</item>
<item>@string/pref_camera_scenemode_entry_promode</item>
<item>@string/pref_camera_scenemode_entry_deepzoom</item>
+ <item>@string/pref_camera_scenemode_entry_deepportrait</item>
</string-array>
<array name="pref_camera2_scenemode_thumbnails" translatable="false">
@@ -214,6 +216,7 @@
<item>@drawable/scene_panorama</item>
<item>@drawable/promode</item>
<item>@drawable/sharp_photo</item>
+ <item>@drawable/deep_portrait</item>
</array>
<array name="pref_camera2_scenemode_black_thumbnails" translatable="false">
@@ -241,6 +244,7 @@
<item>@drawable/ic_scene_mode_black_panorama</item>
<item>@drawable/ic_scene_mode_black_dual_camera</item>
<item>@drawable/ic_scene_mode_black_sharp_photo</item>
+ <item>@drawable/deep_portrait_black</item>
</array>
<!-- Camera Preferences Scene Mode dialog box entries -->
@@ -269,6 +273,7 @@
<item>@string/pref_camera2_scene_mode_panorama_instructional_content</item>
<item>@string/pref_camera2_scene_mode_pro_instructional_content</item>
<item>@string/pref_camera2_scene_mode_deepzoom_instructional_content</item>
+ <item>@string/pref_camera2_scene_mode_deepportrait_instructional_content</item>
</string-array>
<string-array name="pref_camera2_whitebalance_entryvalues" translatable="false">
@@ -1176,4 +1181,10 @@ for time lapse recording -->
<item>@string/pref_camera2_video_hdr_entry_value_disable</item>
<item>@string/pref_camera2_video_hdr_entry_value_enable</item>
</string-array>
+
+ <string-array name="pref_camera2_deepportrait_entryvalues" translatable="false">
+ <item>@string/pref_camera2_deepportrait_entry_value_disable</item>
+ <item>@string/pref_camera2_deepportrait_entry_value_enable</item>
+ </string-array>
+
</resources>
diff --git a/res/values/qcomstrings.xml b/res/values/qcomstrings.xml
index 7074df50d..215669f16 100755
--- a/res/values/qcomstrings.xml
+++ b/res/values/qcomstrings.xml
@@ -1087,7 +1087,7 @@
<string name="pref_camera2_scene_mode_blur_buster_instructional_content" translatable="true">BlurBuster reduces blur from shaky hands.It can be helpful when taking photos in difficult places.</string>
<string name="pref_camera2_scene_mode_pro_instructional_content" translatable="true">With Pro Mode, you can manually control settings for ISO,Exposure, White Balance, and Focus. You will have easy access to all of these advanced settings</string>
<string name="pref_camera2_scene_mode_deepzoom_instructional_content" translatable="true">With DeepZoom Mode, you can use the 2X or 4X to take picture, then you can get the deepzoom`s picture </string>
-
+ <string name="pref_camera2_scene_mode_deepportrait_instructional_content" translatable="true">With DeepPortrait, you can take selfies, with a blurred background. You can use the slider to adjust the amount of the blur</string>
<string name="pref_camera2_not_show_again">Do not show again</string>
<string name="pref_camera2_scene_mode_instructional_ok" translatable="true">OK</string>
@@ -1253,5 +1253,9 @@
<string name="pref_camera2_video_hdr_entry_disable" translatable="true">disable</string>
<string name="pref_camera2_video_hdr_entry_value_enable" translatable="false">1</string>
<string name="pref_camera2_video_hdr_entry_value_disable" translatable="false">0</string>
+
+ <string name="pref_camera2_deepportrait_entry_value_disable" translatable="false">off</string>
+ <string name="pref_camera2_deepportrait_entry_value_enable" translatable="false">on</string>
+ <string name="pref_camera_scenemode_entry_deepportrait" translatable="false">Deepportrait</string>
</resources>
diff --git a/src/com/android/camera/CaptureModule.java b/src/com/android/camera/CaptureModule.java
index 228f4af54..0fda7e213 100755
--- a/src/com/android/camera/CaptureModule.java
+++ b/src/com/android/camera/CaptureModule.java
@@ -66,6 +66,7 @@ import android.media.MediaMetadataRetriever;
import android.media.MediaRecorder;
import android.media.MediaCodecInfo;
import android.net.Uri;
+import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Debug;
import android.os.Handler;
@@ -91,9 +92,14 @@ import android.graphics.Canvas;
import android.graphics.Color;
import android.util.AttributeSet;
+import com.android.camera.deepportrait.CamGLRenderObserver;
+import com.android.camera.deepportrait.CamGLRenderer;
+import com.android.camera.deepportrait.DPImage;
+import com.android.camera.deepportrait.GLCameraPreview;
import com.android.camera.exif.ExifInterface;
import com.android.camera.imageprocessor.filter.BlurbusterFilter;
import com.android.camera.imageprocessor.filter.ChromaflashFilter;
+import com.android.camera.imageprocessor.filter.DeepPortraitFilter;
import com.android.camera.imageprocessor.filter.ImageFilter;
import com.android.camera.imageprocessor.PostProcessor;
import com.android.camera.imageprocessor.FrameProcessor;
@@ -137,7 +143,8 @@ public class CaptureModule implements CameraModule, PhotoController,
MediaSaveService.Listener, ClearSightImageProcessor.Callback,
SettingsManager.Listener, LocationManager.Listener,
CountDownView.OnCountDownFinishedListener,
- MediaRecorder.OnErrorListener, MediaRecorder.OnInfoListener {
+ MediaRecorder.OnErrorListener, MediaRecorder.OnInfoListener,
+ CamGLRenderObserver {
public static final int DUAL_MODE = 0;
public static final int BAYER_MODE = 1;
public static final int MONO_MODE = 2;
@@ -436,6 +443,9 @@ public class CaptureModule implements CameraModule, PhotoController,
private long mIsoExposureTime;
private int mIsoSensitivity;
+ private CamGLRenderer mRenderer;
+ private boolean mDeepPortraitMode = false;
+
private class SelfieThread extends Thread {
public void run() {
try {
@@ -941,6 +951,12 @@ public class CaptureModule implements CameraModule, PhotoController,
return value.equals("enable");
}
+ public boolean isDeepPortraitMode() {
+ String value = mSettingsManager.getValue(SettingsManager.KEY_SCENE_MODE);
+ if (value == null) return false;
+ return Integer.valueOf(value) == SettingsManager.SCENE_MODE_DEEPPORTRAIT_INT;
+ }
+
private boolean isMpoOn() {
String value = mSettingsManager.getValue(SettingsManager.KEY_MPO);
if (value == null) return false;
@@ -974,6 +990,14 @@ public class CaptureModule implements CameraModule, PhotoController,
return CameraProfile.getJpegEncodingQualityParameter(value);
}
+ public CamGLRenderer getCamGLRender() {
+ return mRenderer;
+ }
+
+ public GLCameraPreview getGLCameraPreview() {
+ return mUI.getGLCameraPreview();
+ }
+
public LocationManager getLocationManager() {
return mLocationManager;
}
@@ -1104,7 +1128,8 @@ public class CaptureModule implements CameraModule, PhotoController,
}
}
- private void updatePreviewSurfaceReadyState(boolean rdy) {
+ private void
+ updatePreviewSurfaceReadyState(boolean rdy) {
if (rdy != mSurfaceReady) {
if (rdy) {
Log.i(TAG, "Preview Surface is ready!");
@@ -1201,20 +1226,26 @@ public class CaptureModule implements CameraModule, PhotoController,
Log.d(TAG, "cameracapturesession - onClosed");
}
};
- waitForPreviewSurfaceReady();
- Surface surface = getPreviewSurfaceForSession(id);
- if(id == getMainCameraId()) {
- mFrameProcessor.setOutputSurface(surface);
+ Surface surface = null;
+ if (!mDeepPortraitMode) {
+ waitForPreviewSurfaceReady();
+ surface = getPreviewSurfaceForSession(id);
+
+ if(id == getMainCameraId()) {
+ mFrameProcessor.setOutputSurface(surface);
+ }
}
if(isClearSightOn()) {
- mPreviewRequestBuilder[id].addTarget(surface);
- list.add(surface);
+ if (surface != null) {
+ mPreviewRequestBuilder[id].addTarget(surface);
+ list.add(surface);
+ }
ClearSightImageProcessor.getInstance().createCaptureSession(
id == BAYER_ID, mCameraDevice[id], list, captureSessionCallback);
} else if (id == getMainCameraId()) {
- if(mFrameProcessor.isFrameFilterEnabled()) {
+ if(mFrameProcessor.isFrameFilterEnabled() && !mDeepPortraitMode) {
mActivity.runOnUiThread(new Runnable() {
public void run() {
mUI.getSurfaceHolder().setFixedSize(mPreviewSize.getHeight(), mPreviewSize.getWidth());
@@ -1246,8 +1277,10 @@ public class CaptureModule implements CameraModule, PhotoController,
mCameraDevice[id].createCaptureSession(list, captureSessionCallback, null);
}
} else {
- mPreviewRequestBuilder[id].addTarget(surface);
- list.add(surface);
+ if (surface != null) {
+ mPreviewRequestBuilder[id].addTarget(surface);
+ list.add(surface);
+ }
list.add(mImageReader[id].getSurface());
// Here, we create a CameraCaptureSession for camera preview.
mCameraDevice[id].createCaptureSession(list, captureSessionCallback, null);
@@ -2564,8 +2597,9 @@ public class CaptureModule implements CameraModule, PhotoController,
ClearSightImageProcessor.getInstance().close();
}
closeCamera();
- resetAudioMute();
mUI.showPreviewCover();
+ if (mUI.getGLCameraPreview() != null)
+ mUI.getGLCameraPreview().onPause();
mUI.hideSurfaceView();
mFirstPreviewLoaded = false;
stopBackgroundThread();
@@ -2575,7 +2609,6 @@ public class CaptureModule implements CameraModule, PhotoController,
closeVideoFileDescriptor();
}
- @Override
public void onResumeBeforeSuper() {
// must change cameraId before "mPaused = false;"
int intentCameraId = CameraUtil.getCameraFacingIntentExtras(mActivity);
@@ -2613,6 +2646,11 @@ public class CaptureModule implements CameraModule, PhotoController,
private ArrayList<Integer> getFrameProcFilterId() {
ArrayList<Integer> filters = new ArrayList<Integer>();
+ if(mDeepPortraitMode) {
+ filters.add(FrameProcessor.FILTER_DEEP_PORTRAIT);
+ return filters;
+ }
+
String scene = mSettingsManager.getValue(SettingsManager.KEY_MAKEUP);
if(scene != null && !scene.equalsIgnoreCase("0")) {
filters.add(FrameProcessor.FILTER_MAKEUP);
@@ -2620,7 +2658,6 @@ public class CaptureModule implements CameraModule, PhotoController,
if(isTrackingFocusSettingOn()) {
filters.add(FrameProcessor.LISTENER_TRACKING_FOCUS);
}
-
return filters;
}
@@ -2695,7 +2732,9 @@ public class CaptureModule implements CameraModule, PhotoController,
Log.d(TAG, "updatePreviewSize final preview size = " + width + ", " + height);
mPreviewSize = new Size(width, height);
- mUI.setPreviewSize(mPreviewSize.getWidth(), mPreviewSize.getHeight());
+ if (!mDeepPortraitMode) {
+ mUI.setPreviewSize(mPreviewSize.getWidth(), mPreviewSize.getHeight());
+ }
}
private void openProcessors() {
@@ -2733,11 +2772,11 @@ public class CaptureModule implements CameraModule, PhotoController,
Log.d(TAG, "Chosen postproc filter id : " + getPostProcFilterId(mode));
mPostProcessor.onOpen(getPostProcFilterId(mode), isFlashOn,
isTrackingFocusSettingOn(), isMakeupOn, isSelfieMirrorOn,
- mSaveRaw, mIsSupportedQcfa);
+ mSaveRaw, mIsSupportedQcfa, mDeepPortraitMode);
} else {
mPostProcessor.onOpen(PostProcessor.FILTER_NONE, isFlashOn,
isTrackingFocusSettingOn(), isMakeupOn, isSelfieMirrorOn,
- mSaveRaw, mIsSupportedQcfa);
+ mSaveRaw, mIsSupportedQcfa, mDeepPortraitMode);
}
}
if(mFrameProcessor != null) {
@@ -2759,6 +2798,7 @@ public class CaptureModule implements CameraModule, PhotoController,
public void onResumeAfterSuper() {
Log.d(TAG, "onResume " + getCameraMode());
reinit();
+ mDeepPortraitMode = isDeepPortraitMode();
initializeValues();
updatePreviewSize();
mCameraIdList = new ArrayList<>();
@@ -2794,7 +2834,15 @@ public class CaptureModule implements CameraModule, PhotoController,
msg.arg1 = cameraId;
mCameraHandler.sendMessage(msg);
}
- mUI.showSurfaceView();
+ if (!mDeepPortraitMode) {
+ mUI.showSurfaceView();
+ mUI.stopDeepPortraitMode();
+ } else {
+ mUI.startDeepPortraitMode(mPreviewSize);
+ if (mUI.getGLCameraPreview() != null)
+ mUI.getGLCameraPreview().onResume();
+ }
+
if (!mFirstTimeInitialized) {
initializeFirstTime();
} else {
@@ -3332,6 +3380,15 @@ public class CaptureModule implements CameraModule, PhotoController,
return mOrientation;
}
+ public int getSensorOrientation() {
+ int degree = 0;
+ if(getMainCameraCharacteristics() != null) {
+ degree = getMainCameraCharacteristics().
+ get(CameraCharacteristics.SENSOR_ORIENTATION);
+ }
+ return degree;
+ }
+
@Override
public void onShowSwitcherPopup() {
@@ -5833,6 +5890,39 @@ public class CaptureModule implements CameraModule, PhotoController,
boolean checkSessionAndBuilder(CameraCaptureSession session, CaptureRequest.Builder builder) {
return session != null && builder != null;
}
+
+ public void onRenderComplete(DPImage dpimage, boolean isError) {
+ dpimage.mImage.close();
+ if(isError) {
+ getGLCameraPreview().requestRender();
+ }
+ }
+
+ public void onRenderSurfaceCreated() {
+ updatePreviewSurfaceReadyState(true);
+ mUI.initThumbnail();
+ if (getFrameFilters().size() == 0) {
+ Toast.makeText(mActivity, "DeepPortrait is not supported",
+ Toast.LENGTH_LONG).show();
+ return;
+ }
+ mRenderer = getGLCameraPreview().getRendererInstance();
+ DeepPortraitFilter filter = (DeepPortraitFilter)getFrameFilters().get(0);
+ if (filter != null) {
+ if (filter.getDPInitialized()) {
+ int degree = getSensorOrientation();
+ int adjustedRotation = ( degree - getDisplayOrientation() + 360 ) % 360;
+ int surfaceRotation =
+ 90 * mActivity.getWindowManager().getDefaultDisplay().getRotation();
+ mRenderer.setMaskResolution(filter.getDpMaskWidth(),filter.getDpMaskHieght());
+ mRenderer.setRotationDegree(
+ adjustedRotation, (degree - surfaceRotation + 360) % 360);
+ }
+ }
+ }
+ public void onRenderSurfaceDestroyed() {
+ mRenderer = null;
+ }
}
class Camera2GraphView extends View {
diff --git a/src/com/android/camera/CaptureUI.java b/src/com/android/camera/CaptureUI.java
index 950820fcc..617d9ef71 100755
--- a/src/com/android/camera/CaptureUI.java
+++ b/src/com/android/camera/CaptureUI.java
@@ -46,6 +46,7 @@ import android.renderscript.Type;
import android.text.TextUtils;
import android.util.DisplayMetrics;
import android.util.Log;
+import android.util.Size;
import android.view.Display;
import android.view.Gravity;
import android.view.LayoutInflater;
@@ -65,6 +66,8 @@ import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.SeekBar;
import android.widget.TextView;
+
+import com.android.camera.imageprocessor.filter.DeepPortraitFilter;
import com.android.camera.ui.AutoFitSurfaceView;
import com.android.camera.ui.Camera2FaceView;
import com.android.camera.ui.CameraControls;
@@ -82,7 +85,8 @@ import com.android.camera.ui.SelfieFlashView;
import com.android.camera.ui.TrackingFocusRenderer;
import com.android.camera.ui.ZoomRenderer;
import com.android.camera.util.CameraUtil;
-
+import com.android.camera.deepportrait.CamGLRenderer;
+import com.android.camera.deepportrait.GLCameraPreview;
import org.codeaurora.snapcam.R;
import java.util.List;
@@ -110,6 +114,7 @@ public class CaptureUI implements FocusOverlayManager.FocusUI,
private AutoFitSurfaceView mSurfaceViewMono;
private SurfaceHolder mSurfaceHolder;
private SurfaceHolder mSurfaceHolderMono;
+ private GLCameraPreview mGLSurfaceView = null;
private int mOrientation;
private int mFilterMenuStatus;
private PreviewGestures mGestures;
@@ -188,7 +193,9 @@ public class CaptureUI implements FocusOverlayManager.FocusUI,
private View mSceneModeSwitcher;
private View mFrontBackSwitcher;
private ImageView mMakeupButton;
+ private ImageView mDeepportraitSwitcher;
private SeekBar mMakeupSeekBar;
+ private SeekBar mDeepportraitSeekBar;
private View mMakeupSeekBarLayout;
private View mSeekbarBody;
private TextView mRecordingTimeView;
@@ -199,6 +206,7 @@ public class CaptureUI implements FocusOverlayManager.FocusUI,
private ImageView mSeekbarToggleButton;
private View mProModeCloseButton;
private RotateLayout mSceneModeLabelRect;
+ private LinearLayout mSceneModeLabelView;
private TextView mSceneModeName;
private ImageView mExitBestMode;
private RotateLayout mDeepZoomModeRect;
@@ -241,6 +249,12 @@ public class CaptureUI implements FocusOverlayManager.FocusUI,
}
}
+ public void initThumbnail() {
+ if (mThumbnail == null)
+ mThumbnail = (ImageView) mRootView.findViewById(R.id.preview_thumb);
+ mActivity.updateThumbnail(mThumbnail);
+ }
+
private void previewUIDestroyed() {
mModule.onPreviewUIDestroyed();
}
@@ -293,6 +307,7 @@ public class CaptureUI implements FocusOverlayManager.FocusUI,
mFrontBackSwitcher = mRootView.findViewById(R.id.front_back_switcher);
mMakeupButton = (ImageView) mRootView.findViewById(R.id.ts_makeup_switcher);
mMakeupSeekBarLayout = mRootView.findViewById(R.id.makeup_seekbar_layout);
+ mDeepportraitSwitcher = (ImageView) mRootView.findViewById(R.id.deepportrait_switcher);
mSeekbarBody = mRootView.findViewById(R.id.seekbar_body);
mSeekbarToggleButton = (ImageView) mRootView.findViewById(R.id.seekbar_toggle);
mSeekbarToggleButton.setOnClickListener(new View.OnClickListener() {
@@ -323,6 +338,29 @@ public class CaptureUI implements FocusOverlayManager.FocusUI,
public void onStopTrackingTouch(SeekBar seekBar) {
}
});
+ mDeepportraitSeekBar = (SeekBar)mRootView.findViewById(R.id.deepportrait_seekbar);
+ mDeepportraitSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
+ @Override
+ public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
+ if (mModule.getCamGLRender() != null) {
+ module.getCamGLRender().setBlurLevel(progress);
+ }
+ }
+
+ @Override
+ public void onStartTrackingTouch(SeekBar seekBar) {
+
+ }
+
+ @Override
+ public void onStopTrackingTouch(SeekBar seekBar) {
+ final SharedPreferences prefs =
+ PreferenceManager.getDefaultSharedPreferences(mActivity);
+ SharedPreferences.Editor editor = prefs.edit();
+ editor.putInt(SettingsManager.KEY_DEEPPORTRAIT_VALUE, seekBar.getProgress());
+ editor.commit();
+ }
+ });
mMakeupButton.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v) {
@@ -333,6 +371,26 @@ public class CaptureUI implements FocusOverlayManager.FocusUI,
}
});
setMakeupButtonIcon();
+
+ mDeepportraitSwitcher.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ if (module != null && !module.isAllSessionClosed()) {
+ String value = mSettingsManager.getValue(SettingsManager.KEY_SCENE_MODE);
+ if(value == null ||
+ Integer.valueOf(value) != SettingsManager.SCENE_MODE_DEEPPORTRAIT_INT) {
+ mSettingsManager.setValue(SettingsManager.KEY_SCENE_MODE,""+
+ SettingsManager.SCENE_MODE_DEEPPORTRAIT_INT);
+ } else {
+ mSettingsManager.setValue(SettingsManager.KEY_SCENE_MODE,
+ ""+SettingsManager.SCENE_MODE_AUTO_INT);
+ }
+ }
+ setDeepportraitButtonIcon();
+ }
+ });
+ setDeepportraitButtonIcon();
+
mFlashButton = (FlashToggleButton) mRootView.findViewById(R.id.flash_button);
mProModeCloseButton = mRootView.findViewById(R.id.promode_close_button);
mProModeCloseButton.setOnClickListener(new View.OnClickListener() {
@@ -584,6 +642,20 @@ public class CaptureUI implements FocusOverlayManager.FocusUI,
return mDeepZoomValue;
}
+ private void setDeepportraitButtonIcon() {
+ boolean enable = DeepPortraitFilter.isSupportedStatic();
+ mDeepportraitSwitcher.setEnabled(enable);
+ mActivity.runOnUiThread(new Runnable() {
+ public void run() {
+ if(mModule.isDeepPortraitMode()) {
+ mDeepportraitSwitcher.setImageResource(R.drawable.deep_portrait_on);
+ } else {
+ mDeepportraitSwitcher.setImageResource(R.drawable.deep_portrait);
+ }
+ }
+ });
+ }
+
public void onCameraOpened(List<Integer> cameraIds) {
mGestures.setCaptureUI(this);
if (mModule.isDeepZoom()) {
@@ -599,6 +671,7 @@ public class CaptureUI implements FocusOverlayManager.FocusUI,
initFilterModeButton();
initFlashButton();
setMakeupButtonIcon();
+ setDeepportraitButtonIcon();
showSceneModeLabel();
updateMenus();
if(mModule.isTrackingFocusSettingOn()) {
@@ -912,7 +985,12 @@ public class CaptureUI implements FocusOverlayManager.FocusUI,
mIsSceneModeLabelClose = false;
int index = mSettingsManager.getValueIndex(SettingsManager.KEY_SCENE_MODE);
CharSequence sceneModeNameArray[] = mSettingsManager.getEntries(SettingsManager.KEY_SCENE_MODE);
- if ( index > 0 && index < sceneModeNameArray.length ) {
+ if (mModule.isDeepPortraitMode()) {
+ mSceneModeLabelRect.setVisibility(View.GONE);
+ mExitBestMode.setVisibility(View.GONE);
+ return;
+ }
+ if ( index > 0 && index < sceneModeNameArray.length) {
mSceneModeName.setText(sceneModeNameArray[index]);
mSceneModeLabelRect.setVisibility(View.VISIBLE);
mExitBestMode.setVisibility(View.VISIBLE);
@@ -947,6 +1025,7 @@ public class CaptureUI implements FocusOverlayManager.FocusUI,
if(value != null && value.equals("0")) {
mMakeupButton.setVisibility(View.INVISIBLE);
}
+ mDeepportraitSwitcher.setVisibility(View.INVISIBLE);
mIsVideoUI = true;
mPauseButton.setVisibility(View.VISIBLE);
}
@@ -1182,6 +1261,7 @@ public class CaptureUI implements FocusOverlayManager.FocusUI,
if (mFilterModeSwitcher != null) mFilterModeSwitcher.setVisibility(status);
if (mFilterModeSwitcher != null) mFilterModeSwitcher.setVisibility(status);
if (mMakeupButton != null) mMakeupButton.setVisibility(status);
+ if (mDeepportraitSwitcher != null) mDeepportraitSwitcher.setVisibility(status);
}
public void initializeControlByIntent() {
@@ -1227,6 +1307,38 @@ public class CaptureUI implements FocusOverlayManager.FocusUI,
mActivity.setSystemBarsVisibility(false);
}
+ public void startDeepPortraitMode(Size preview) {
+ mSurfaceView.setVisibility(View.GONE);
+ mSurfaceViewMono.setVisibility(View.GONE);
+ mGLSurfaceView = new GLCameraPreview(
+ mActivity, preview.getWidth(), preview.getHeight(), mModule);
+ FrameLayout layout = (FrameLayout) mActivity.findViewById(R.id.camera_glpreview);
+ layout.addView(mGLSurfaceView);
+ mGLSurfaceView.setVisibility(View.VISIBLE);
+ mRootView.requestLayout();
+ final SharedPreferences prefs =
+ PreferenceManager.getDefaultSharedPreferences(mActivity);
+ int progress = prefs.getInt(SettingsManager.KEY_DEEPPORTRAIT_VALUE,50);
+ mDeepportraitSeekBar.setProgress(progress);
+ mDeepportraitSeekBar.setVisibility(View.VISIBLE);
+ mRenderOverlay.setVisibility(View.GONE);
+ }
+
+ public void stopDeepPortraitMode() {
+ FrameLayout layout = (FrameLayout)mActivity.findViewById(R.id.camera_glpreview);
+ if (mGLSurfaceView != null) {
+ mGLSurfaceView.setVisibility(View.GONE);
+ layout.removeView(mGLSurfaceView);
+ }
+ mGLSurfaceView = null;
+ mDeepportraitSeekBar.setVisibility(View.GONE);
+ mRenderOverlay.setVisibility(View.VISIBLE);
+ }
+
+ public GLCameraPreview getGLCameraPreview() {
+ return mGLSurfaceView;
+ }
+
public void updateMenus() {
boolean enableMakeupMenu = true;
boolean enableFilterMenu = true;
@@ -1652,7 +1764,7 @@ public class CaptureUI implements FocusOverlayManager.FocusUI,
if (mGestures != null) {
mGestures.setEnabled(previewFocused);
}
- if (mRenderOverlay != null) {
+ if (mRenderOverlay != null && !mModule.isDeepPortraitMode()) {
// this can not happen in capture mode
mRenderOverlay.setVisibility(previewFocused ? View.VISIBLE : View.GONE);
}
diff --git a/src/com/android/camera/SettingsManager.java b/src/com/android/camera/SettingsManager.java
index 410f2a8fd..c75f31809 100755
--- a/src/com/android/camera/SettingsManager.java
+++ b/src/com/android/camera/SettingsManager.java
@@ -52,6 +52,7 @@ import com.android.camera.imageprocessor.filter.BeautificationFilter;
import com.android.camera.imageprocessor.filter.BestpictureFilter;
import com.android.camera.imageprocessor.filter.BlurbusterFilter;
import com.android.camera.imageprocessor.filter.ChromaflashFilter;
+import com.android.camera.imageprocessor.filter.DeepPortraitFilter;
import com.android.camera.imageprocessor.filter.OptizoomFilter;
import com.android.camera.imageprocessor.filter.SharpshooterFilter;
import com.android.camera.imageprocessor.filter.StillmoreFilter;
@@ -100,6 +101,7 @@ public class SettingsManager implements ListMenu.SettingsListener {
public static final int SCENE_MODE_TRACKINGFOCUS_INT = SCENE_MODE_CUSTOM_START + 8;
public static final int SCENE_MODE_PROMODE_INT = SCENE_MODE_CUSTOM_START + 9;
public static final int SCENE_MODE_DEEPZOOM_INT = SCENE_MODE_CUSTOM_START + 10;
+ public static final int SCENE_MODE_DEEPPORTRAIT_INT = SCENE_MODE_CUSTOM_START + 11;
public static final String SCENE_MODE_DUAL_STRING = "100";
public static final String KEY_CAMERA_SAVEPATH = "pref_camera2_savepath_key";
public static final String KEY_RECORD_LOCATION = "pref_camera2_recordlocation_key";
@@ -160,6 +162,7 @@ public class SettingsManager implements ListMenu.SettingsListener {
public static final String KEY_QCFA = "pref_camera2_qcfa_key";
public static final String KEY_EIS_VALUE = "pref_camera2_eis_key";
public static final String KEY_FOVC_VALUE = "pref_camera2_fovc_key";
+ public static final String KEY_DEEPPORTRAIT_VALUE = "pref_camera2_deepportrait_key";
public static final HashMap<String, Integer> KEY_ISO_INDEX = new HashMap<String, Integer>();
public static final String KEY_BSGC_DETECTION = "pref_camera2_bsgc_key";
@@ -1229,12 +1232,20 @@ public class SettingsManager implements ListMenu.SettingsListener {
Size[] sizes = map.getOutputSizes(ImageFormat.JPEG);
List<String> res = new ArrayList<>();
+ boolean isDeepportrait = getDeepportraitEnabled();
+
if (getQcfaPrefEnabled() && getIsSupportedQcfa(cameraId)) {
res.add(getSupportedQcfaDimension(cameraId));
}
if (sizes != null) {
for (int i = 0; i < sizes.length; i++) {
+ if (isDeepportrait &&
+ (Math.min(sizes[i].getWidth(),sizes[i].getHeight()) < 720 ||
+ Math.max(sizes[i].getWidth(),sizes[i].getHeight()) <= 1024)) {
+ //some reslutions are not supported in deepportrait
+ continue;
+ }
res.add(sizes[i].toString());
}
}
@@ -1352,7 +1363,7 @@ public class SettingsManager implements ListMenu.SettingsListener {
if (BlurbusterFilter.isSupportedStatic()) modes.add(SCENE_MODE_BLURBUSTER_INT + "");
if (SharpshooterFilter.isSupportedStatic()) modes.add(SCENE_MODE_SHARPSHOOTER_INT + "");
if (TrackingFocusFrameListener.isSupportedStatic()) modes.add(SCENE_MODE_TRACKINGFOCUS_INT + "");
- if (DeepZoomFilter.isSupportedStatic()) modes.add(SCENE_MODE_DEEPZOOM_INT + "");
+ if (DeepPortraitFilter.isSupportedStatic()) modes.add(SCENE_MODE_DEEPPORTRAIT_INT+"");
modes.add("" + SCENE_MODE_PROMODE_INT);
for (int mode : sceneModes) {
modes.add("" + mode);
@@ -1518,14 +1529,21 @@ public class SettingsManager implements ListMenu.SettingsListener {
}
public boolean getQcfaPrefEnabled() {
- ListPreference qcfaPref = mPreferenceGroup.findPreference(KEY_QCFA);
- String qcfa = qcfaPref.getValue();
+ String qcfa = getValue(KEY_QCFA);
if(qcfa != null && qcfa.equals("enable")) {
return true;
}
return false;
}
+ public boolean getDeepportraitEnabled() {
+ String dp = getValue(KEY_SCENE_MODE);
+ if( dp!= null && Integer.valueOf(dp) == SCENE_MODE_DEEPPORTRAIT_INT) {
+ return true;
+ }
+ return false;
+ }
+
public boolean getIsSupportedQcfa (int cameraId) {
byte isSupportQcfa = 0;
try {
diff --git a/src/com/android/camera/deepportrait/CamGLRenderObserver.java b/src/com/android/camera/deepportrait/CamGLRenderObserver.java
new file mode 100755
index 000000000..53faa4543
--- /dev/null
+++ b/src/com/android/camera/deepportrait/CamGLRenderObserver.java
@@ -0,0 +1,40 @@
+/*
+ * 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 com.android.camera.deepportrait;
+
+// Wrapper for native library
+
+public interface CamGLRenderObserver
+{
+ public void onRenderComplete(DPImage dpimage, boolean isError);
+ public void onRenderSurfaceCreated();
+ public void onRenderSurfaceDestroyed();
+}
diff --git a/src/com/android/camera/deepportrait/CamGLRenderer.java b/src/com/android/camera/deepportrait/CamGLRenderer.java
new file mode 100755
index 000000000..ef8e3b1f4
--- /dev/null
+++ b/src/com/android/camera/deepportrait/CamGLRenderer.java
@@ -0,0 +1,695 @@
+/*
+ * 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 com.android.camera.deepportrait;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.FloatBuffer;
+import java.nio.ShortBuffer;
+import java.util.Vector;
+import java.lang.Thread;
+import android.media.Image;
+import android.media.Image.Plane;
+
+import javax.microedition.khronos.egl.EGLConfig;
+import javax.microedition.khronos.opengles.GL10;
+
+import android.content.Context;
+import android.opengl.GLES30;
+import android.opengl.GLSurfaceView;
+import android.opengl.GLSurfaceView.Renderer;
+import android.opengl.Matrix;
+import android.util.Log;
+
+
+public class CamGLRenderer implements Renderer
+{
+ // MVP
+ private final float[] mtrxProjection = new float[16];
+ private final float[] mtrxView = new float[16];
+ private final float[] mtrxProjectionAndView = new float[16];
+ // Vertex shader points
+
+ public FloatBuffer mSquareVertices;
+ public FloatBuffer[] mSquareTextureCoordinates = new FloatBuffer[4]; // 4 positions
+ // synchronized vector
+ private Vector<DPImage> mFrameQueue;
+
+ private final boolean SHOW_LOGS = false;
+
+ /** Program handles */
+ private int mConvertProgramHandle;
+ private int mBlurProgramHandle;
+ private int mProgramHandle;
+ private Boolean mActive = false;
+
+ // Effects
+ Boolean mBokehEffect = true;
+
+ // Our screenresolution
+ float mScreenWidth = 0;
+ float mScreenHeight = 0;
+
+ // Our screenresolution
+ int mScreenROIX = 0;
+ int mScreenROIY = 0;
+ int mScreenROIWidth = 0;
+ int mScreenROIHeight = 0;
+
+ //Display image resolution
+ int mFrameWidth = 0;
+ int mFrameHeight = 0;
+
+ // Misc
+ Context mContext;
+ long mLastTime;
+ int mProgram;
+ private CamRenderTexture mCamTexture;
+
+ private ByteBuffer scratchRGB;
+ private CamGLRenderObserver mObserver;
+
+ private final int NUM_PROGRAMS = 3;
+ private int[] mVerticesHandle = new int[NUM_PROGRAMS];
+ private int[] mTexCoordLocHandle = new int[NUM_PROGRAMS];
+ private int[] mMVPMtrxhandle = new int[NUM_PROGRAMS];
+ private int mRotMtrxhandle;
+ private int mSurfaceRotMtrxhandle;
+ private int mFlipMtrxhandle;
+ private int mInYHandle;
+ private int mInCHandle;
+ private int mPositionConv;
+ private int[] mInRGBHandle = new int[8];
+ private int mForegroundRGBHandle;
+ private int mBackGroundRGBHandle;
+ private int mMaskHandle;
+ private int mXPixelOffsetUniform;
+ private int mYPixelOffsetUniform;
+ private int mMipLevelUniform;
+ private int mBlurLevel = 50;
+ private int mRotationDegree = 90;
+ private int mMaskWidth = 0;
+ private int mMaskHeight = 0;
+ private boolean mTexturesCreated = false;
+ private static final String TAG = "<dp><app><CamGLRenderer>";
+ private long prevTime, currentTime;
+ private long minFrameDelta = 33;
+ private int mFrameRotation = 0;
+
+ private final CamRenderTexture.BlurType blurType = CamRenderTexture.BlurType.BlurTypeGaussianDilated;
+
+ private final boolean ROTATE_MASK = false;
+
+ private final float[] flipNone = new float[] { 1.0f, 0.0f, 1.0f, 0.0f }; // x, 1-x, y, 1-y
+ private final float[] flipX = new float[] { 0.0f, 1.0f, 1.0f, 0.0f }; // x, 1-x, y, 1-y
+ private final float[] flipY = new float[] { 1.0f, 0.0f, 0.0f, 1.0f }; // x, 1-x, y, 1-y
+ private final float[] flipXY = new float[] { 0.0f, 1.0f, 0.0f, 1.0f }; // x, 1-x, y, 1-y
+
+ // clockwise rotations. All in column major
+ private final float[] rotNone = new float[] { 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f };
+ // rotmatrix of 90 + move to 1st quadrant
+ private final float[] rot90 = new float[] { 0.0f, -1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f }; // 1-y, x
+ // rotmatrix of 180 + move to 1st quadrant
+ private final float[] rot180 = new float[] { -1.0f, 0.0f, 1.0f, 0.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f };
+ // rotmatrix of 270 + move to 1st quadrant
+ private final float[] rot270 = new float[] { 0.0f, 1.0f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f }; // y, 1-x
+
+ private float[] mRotationMatrix = new float[9];
+ private float[] mSurfaceRotationMatrix = new float[9];
+ private GLSurfaceView mSurfaceView;
+
+ public void sendFrame( DPImage dpimage )
+ {
+ if ( !mActive ) return;
+ synchronized ( mFrameQueue ) {
+ if ( mFrameQueue.size() > 3 ) {
+ DPImage oldImage = mFrameQueue.get( 0 );
+ mFrameQueue.removeElementAt( 0 );
+ mObserver.onRenderComplete( oldImage, true );
+ }
+ mFrameQueue.add( dpimage );
+ }
+ }
+
+ public void setBlurLevel( int level )
+ {
+ mBlurLevel = level;
+ Log.e( TAG, "Blur Level " + mBlurLevel );
+ }
+
+ public void setRotationDegree( int camRotation, int frameRotation )
+ {
+ System.arraycopy( getRotationMatrix3x3( frameRotation ), 0, mSurfaceRotationMatrix, 0, 9 );
+
+ mFrameRotation = frameRotation;
+ mRotationDegree = ( camRotation + frameRotation ) % 360 ;
+ System.arraycopy( getRotationMatrix3x3( mRotationDegree ), 0, mRotationMatrix, 0, 9 );
+ switch ( camRotation ) {
+ case 90:
+ // transpose applied. apply H flip for 90 degree rotation - 1st column
+ mRotationMatrix[0] *= -1;
+ mRotationMatrix[1] *= -1;
+ mRotationMatrix[2] = mRotationMatrix[2] > 0.0f ? 0.0f : 1.0f;
+ break;
+ case 180:
+ // V flip applied. apply H flip for 180 degree rotation.
+ mRotationMatrix[0] *= -1;
+ mRotationMatrix[1] *= -1;
+ mRotationMatrix[2] = mRotationMatrix[2] > 0.0f ? 0.0f : 1.0f;
+ break;
+ case 270:
+ // transpose + H flip applied. correct rotation. No op
+ break;
+ }
+ Log.e( TAG, "setRotationDegree cam " + camRotation + " adjusted " + mRotationDegree +
+ " frame " + frameRotation );
+ }
+
+ public void prepareRotationMatrix( int camRotation )
+ {
+ mRotationDegree = mFrameRotation;
+ System.arraycopy( getRotationMatrix3x3( mRotationDegree ), 0, mRotationMatrix, 0, 9 );
+ if ( ROTATE_MASK ) {
+ switch ( camRotation ) {
+ case 90:
+ // H flip applied. apply V flip for 90 degree rotation - 1st column
+ mRotationMatrix[0] *= -1;
+ mRotationMatrix[1] *= -1;
+ mRotationMatrix[2] = mRotationMatrix[2] > 0.0f ? 0.0f : 1.0f;
+ break;
+ case 180:
+ // V flip applied. apply V flip for 180 degree rotation.
+ mRotationMatrix[3] *= -1;
+ mRotationMatrix[4] *= -1;
+ mRotationMatrix[5] = mRotationMatrix[5] > 0.0f ? 0.0f : 1.0f;
+ break;
+ }
+ }
+ Log.e( TAG, "setRotationDegree per frame single cam " + camRotation + " adjusted " + mRotationDegree +
+ " frame " + mFrameRotation );
+ }
+
+ public void setMaskResolution( int width, int height )
+ {
+ mMaskWidth = width;
+ mMaskHeight = height;
+ Log.e( TAG, "setMaskResolution width " + width + " height " + height );
+ }
+
+ public float[] getRotationMatrix( int rotationDegree )
+ {
+ float[] rotMat = new float[4];
+ float cosTheta = (float)Math.cos( Math.toRadians( rotationDegree ) );
+ float sinTheta = (float)Math.sin( Math.toRadians( rotationDegree ) );
+ rotMat[0] = cosTheta;
+ rotMat[1] = -sinTheta;
+ rotMat[2] = sinTheta;
+ rotMat[3] = cosTheta;
+ return rotMat;
+ }
+
+ public float[] getRotationMatrix3x3( int rotationDegree )
+ {
+ switch ( rotationDegree ) {
+ case 90: return rot90;
+ case 180: return rot180;
+ case 270: return rot270;
+ }
+ return rotNone;
+ }
+
+ public float[] getFlipMatrix( int rotationDegree )
+ {
+ switch ( rotationDegree ) {
+ case 90: return flipX;
+ case 180: return flipY;
+ case 270: return flipXY;
+ }
+ return flipNone;
+ }
+
+ public CamGLRenderer( Context c, int textureWidth, int textureHeight,
+ CamGLRenderObserver observer, GLSurfaceView surfaceView )
+ {
+ mObserver = observer;
+ mContext = c;
+ mCamTexture = new CamRenderTexture();
+ mFrameQueue = new Vector<DPImage>(5);
+ mSurfaceView = surfaceView;
+
+ // Create our UV coordinates.
+ float[] squareTextureCoordinateData = new float[] {
+ 0.0f, 0.0f,
+ 1.0f, 0.0f,
+ 0.0f, 1.0f,
+ 1.0f, 1.0f
+ };
+ float[] squareTextureCoordinateDataHFlip = new float[] {
+ 1.0f, 0.0f,
+ 0.0f, 0.0f,
+ 1.0f, 1.0f,
+ 0.0f, 1.0f
+ };
+ float[] squareTextureCoordinateDataVFlip = new float[] {
+ 0.0f, 1.0f,
+ 1.0f, 1.0f,
+ 0.0f, 0.0f,
+ 1.0f, 0.0f
+ };
+ float[] squareTextureCoordinateDataHVFlip = new float[] {
+ 1.0f, 1.0f,
+ 0.0f, 1.0f,
+ 1.0f, 0.0f,
+ 0.0f, 0.0f
+ };
+ // We have to create the vertices of our triangle.
+ float[] squareVerticesData = new float[] {
+ -1.0f, -1.0f,
+ 1.0f, -1.0f,
+ -1.0f, 1.0f,
+ 1.0f, 1.0f,
+ };
+
+ // The texture buffer
+ for ( int i = 0; i < 4; ++i ) {
+ mSquareTextureCoordinates[i] = ByteBuffer.allocateDirect(
+ squareTextureCoordinateData.length * 4 ).order(
+ ByteOrder.nativeOrder() ).asFloatBuffer();
+ }
+ mSquareTextureCoordinates[0].put( squareTextureCoordinateData ).position( 0 );
+ mSquareTextureCoordinates[1].put( squareTextureCoordinateDataHFlip ).position( 0 );
+ mSquareTextureCoordinates[2].put( squareTextureCoordinateDataVFlip ).position( 0 );
+ mSquareTextureCoordinates[3].put( squareTextureCoordinateDataHVFlip ).position( 0 );
+
+ // The vertex buffer.
+ mSquareVertices = ByteBuffer.allocateDirect( squareVerticesData.length * 4 ).order(
+ ByteOrder.nativeOrder() ).asFloatBuffer();
+ mSquareVertices.put( squareVerticesData ).position(0);
+
+ // initialize bytebuffer for the draw list
+ // short[] drawIndicesData = new short[] {0, 1, 2, 0, 2, 3}; // The order of vertex rendering.
+ // mSquareDrawIndices = ByteBuffer.allocateDirect( drawIndicesData.length * 2).order(
+ // ByteOrder.nativeOrder() ).asShortBuffer();
+ // mSquareDrawIndices.put( drawIndicesData ).position(0);
+
+ mFrameHeight = textureHeight;
+ mFrameWidth = textureWidth;
+ // mRotationMatrix = getRotationMatrix( 90 );
+ mTexturesCreated = false;
+ prevTime = System.currentTimeMillis();
+ }
+
+ public void onPause()
+ {
+ mActive = false;
+ }
+
+ public void onResume()
+ {
+ mActive = true;
+ }
+
+ public void open()
+ {
+ }
+
+ public void close()
+ {
+ mFrameHeight = 0;
+ mFrameWidth = 0;
+ mCamTexture.deleteTextures();
+ mCamTexture = null;
+ }
+
+ @Override
+ public void onSurfaceCreated( GL10 gl, EGLConfig config )
+ {
+ Thread.currentThread().setPriority(Thread.MAX_PRIORITY);
+ // Set the clear color to black
+ GLES30.glClearColor( 0.0f, 0.0f, 0.0f, 1 );
+
+ // Set the camera position (View matrix)
+ Matrix.setLookAtM( mtrxView, 0, 0f, 0f, 1f, 0f, 0f, 0f, 0f, 1.0f, 0.0f );
+
+ int convertVertexShaderHandle = CamRenderShader.compileShader(
+ GLES30.GL_VERTEX_SHADER, getShaderByName("convVertexShaderSource"));
+ int normalVertexShaderHandle = CamRenderShader.compileShader(
+ GLES30.GL_VERTEX_SHADER, getShaderByName("norVertexShaderSource"));
+ int vertexShaderHandle = CamRenderShader.compileShader(
+ GLES30.GL_VERTEX_SHADER, getShaderByName("vertexShaderSource"));
+ int convertShaderHandle = CamRenderShader.compileShader(
+ GLES30.GL_FRAGMENT_SHADER, getShaderByName("convertShaderSource"));
+ int blurShaderHandle = CamRenderShader.compileShader(
+ GLES30.GL_FRAGMENT_SHADER, getShaderByName("blurShaderRGBSource"));
+ int fragmentShaderHandle = CamRenderShader.compileShader(
+ GLES30.GL_FRAGMENT_SHADER, getShaderByName("blendFragShaderRGBSource"));
+
+ //---------------- Convert shader program -----------------------------------------------------
+ mConvertProgramHandle = CamRenderShader.createAndLinkProgram( convertVertexShaderHandle, convertShaderHandle );
+ mVerticesHandle[0] = GLES30.glGetAttribLocation( mConvertProgramHandle, "vPosition" );
+ mTexCoordLocHandle[0] = GLES30.glGetAttribLocation( mConvertProgramHandle, "a_texCoord" );
+ mMVPMtrxhandle[0] = GLES30.glGetUniformLocation( mConvertProgramHandle, "uMVPMatrix" );
+ mPositionConv = GLES30.glGetUniformLocation( mConvertProgramHandle, "positionConv" );
+ mInYHandle = GLES30.glGetUniformLocation( mConvertProgramHandle, "y_texture" );
+ mInCHandle = GLES30.glGetUniformLocation( mConvertProgramHandle, "uv_texture" );
+ //----------------------------------------------------------------------------------------------
+
+ //---------------- Blur + Blend shader program --------------------------------------------------------
+ // mProgramHandle = CamRenderShader.createAndLinkProgram( vertexShaderHandle, fragmentShaderHandle );
+ // mVerticesHandle[1] = GLES30.glGetAttribLocation( mProgramHandle, "vPosition" );
+ // mTexCoordLocHandle[1] = GLES30.glGetAttribLocation( mProgramHandle, "a_texCoord" );
+ // mMVPMtrxhandle[1] = GLES30.glGetUniformLocation( mProgramHandle, "uMVPMatrix" );
+ // mInRGBHandle = GLES30.glGetUniformLocation( mProgramHandle, "rgb_texture" );
+ // mBackGroundRGBHandle = GLES30.glGetUniformLocation( mProgramHandle, "bg_rgb_texture" );
+ // mMaskHandle = GLES30.glGetUniformLocation( mProgramHandle, "mask_texture" );
+ // mXPixelOffsetUniform = GLES30.glGetUniformLocation( mProgramHandle, "xPixelBaseOffset" );
+ // mYPixelOffsetUniform = GLES30.glGetUniformLocation( mProgramHandle, "yPixelBaseOffset" );
+ // mMipLevelUniform = GLES30.glGetUniformLocation( mProgramHandle, "mipLevel" );
+ //----------------------------------------------------------------------------------------------
+
+ //---------------- Blur shader program --------------------------------------------------------
+ mBlurProgramHandle = CamRenderShader.createAndLinkProgram( normalVertexShaderHandle, blurShaderHandle );
+ mVerticesHandle[2] = GLES30.glGetAttribLocation( mBlurProgramHandle, "vPosition" );
+ mTexCoordLocHandle[2] = GLES30.glGetAttribLocation( mBlurProgramHandle, "a_texCoord" );
+ mMVPMtrxhandle[2] = GLES30.glGetUniformLocation( mBlurProgramHandle, "uMVPMatrix" );
+ for ( int i = 0; i < 8; ++i ) {
+ mInRGBHandle[i] = GLES30.glGetUniformLocation( mBlurProgramHandle, "rgb_texture");
+ }
+ mXPixelOffsetUniform = GLES30.glGetUniformLocation( mBlurProgramHandle, "xPixelBaseOffset" );
+ mYPixelOffsetUniform = GLES30.glGetUniformLocation( mBlurProgramHandle, "yPixelBaseOffset" );
+ mMipLevelUniform = GLES30.glGetUniformLocation( mBlurProgramHandle, "mipLevel" );
+ //----------------------------------------------------------------------------------------------
+
+ //---------------- Blend shader program --------------------------------------------------------
+ mProgramHandle = CamRenderShader.createAndLinkProgram( vertexShaderHandle, fragmentShaderHandle );
+ mVerticesHandle[1] = GLES30.glGetAttribLocation( mProgramHandle, "vPosition" );
+ mTexCoordLocHandle[1] = GLES30.glGetAttribLocation( mProgramHandle, "a_texCoord" );
+ mMVPMtrxhandle[1] = GLES30.glGetUniformLocation( mProgramHandle, "uMVPMatrix" );
+ mForegroundRGBHandle = GLES30.glGetUniformLocation( mProgramHandle, "rgb_texture" );
+ mBackGroundRGBHandle = GLES30.glGetUniformLocation( mProgramHandle, "bg_rgb_texture" );
+ mMaskHandle = GLES30.glGetUniformLocation( mProgramHandle, "mask_texture" );
+ mRotMtrxhandle = GLES30.glGetUniformLocation( mProgramHandle, "rotMat" );
+ mSurfaceRotMtrxhandle = GLES30.glGetUniformLocation( mProgramHandle, "surfaceRotMat" );
+ mFlipMtrxhandle = GLES30.glGetUniformLocation( mProgramHandle, "flipMat" );
+ //----------------------------------------------------------------------------------------------
+
+ mActive = true;
+ }
+
+ @Override
+ public void onSurfaceChanged( GL10 gl, int width, int height )
+ {
+
+ // We need to know the current width and height.
+ mScreenWidth = width;
+ mScreenHeight = height;
+ float aspectRatio = (float)mFrameWidth/mFrameHeight;
+ float screenAspectRatio = (float)mScreenWidth/mScreenHeight;
+ Log.d(TAG,"onSurfaceChanged aspectRatio="+aspectRatio+" screenAspectRatio="+screenAspectRatio+" w="+width+" h="+height);
+
+ if ( screenAspectRatio > aspectRatio ) {
+ mScreenROIWidth = (int)Math.min( mScreenWidth, mScreenWidth * aspectRatio / screenAspectRatio );
+ mScreenROIHeight = (int)mScreenHeight;
+ } else {
+ mScreenROIWidth = (int) mScreenWidth;
+ mScreenROIHeight = (int) Math.min( mScreenHeight, mScreenWidth * aspectRatio);
+ }
+ mScreenROIX = ( (int)mScreenWidth - mScreenROIWidth )/2;
+ mScreenROIY = ( (int)mScreenHeight - mScreenROIHeight )/2;
+
+ // Clear our matrices
+ for ( int i = 0; i < 16; i++ ) {
+ mtrxProjection[i] = 0.0f;
+ mtrxProjectionAndView[i] = 0.0f;
+ }
+
+ Log.e( TAG, "onSurfaceChanged Frame_dim " + mFrameWidth + " x " + mFrameHeight +
+ " ROI ( " + mScreenROIX + " " + mScreenROIY +
+ " " + mScreenROIWidth + " " + mScreenROIHeight + ")" );
+ // Setup our screen width and height for normal sprite translation.
+ Matrix.orthoM( mtrxProjection, 0, -aspectRatio, aspectRatio, -1, 1, 0, 50 );
+
+ // Calculate the projection and view transformation
+ Matrix.multiplyMM( mtrxProjectionAndView, 0, mtrxProjection, 0, mtrxView, 0 );
+ }
+
+ public void executeConverter( ByteBuffer bufferY, ByteBuffer bufferC, boolean offline )
+ {
+ // clear Screen and Depth Buffer, we have set the clear color as black.
+ GLES30.glClear( GLES30.GL_COLOR_BUFFER_BIT );
+
+ if ( offline ) {
+ GLES30.glViewport( 0, 0, ( int )mFrameWidth, ( int )mFrameHeight );
+ GLES30.glBindFramebuffer( GLES30.GL_FRAMEBUFFER, mCamTexture.getInRGBFBO( 0 ) );
+ GLES30.glFramebufferTexture2D( GLES30.GL_FRAMEBUFFER, GLES30.GL_COLOR_ATTACHMENT0,
+ GLES30.GL_TEXTURE_2D, mCamTexture.getInRGBTex( 0 ), 0 );
+ } else {
+ GLES30.glViewport( 0, 0, ( int )mScreenWidth, ( int )mScreenHeight );
+ }
+
+ GLES30.glActiveTexture( GLES30.GL_TEXTURE0 );
+ GLES30.glBindTexture( GLES30.GL_TEXTURE_2D, mCamTexture.getInYTex() );
+ GLES30.glTexSubImage2D( GLES30.GL_TEXTURE_2D, 0, 0, 0, mFrameWidth, mFrameHeight,
+ GLES30.GL_LUMINANCE, GLES30.GL_UNSIGNED_BYTE, bufferY );
+
+ GLES30.glActiveTexture( GLES30.GL_TEXTURE1 );
+ GLES30.glBindTexture( GLES30.GL_TEXTURE_2D, mCamTexture.getInCTex() );
+ GLES30.glTexSubImage2D( GLES30.GL_TEXTURE_2D, 0, 0, 0, mFrameWidth/2, mFrameHeight/2,
+ GLES30.GL_LUMINANCE_ALPHA, GLES30.GL_UNSIGNED_BYTE, bufferC );
+
+ GLES30.glUseProgram( mConvertProgramHandle );
+ if (offline) {
+ GLES30.glUniform1i(mPositionConv,0);
+ } else {
+ GLES30.glUniform1i(mPositionConv,1);
+ }
+ GLES30.glUniform1i ( mInYHandle, 0 );
+ GLES30.glUniform1i ( mInCHandle, 1 );
+ GLES30.glVertexAttribPointer( mVerticesHandle[0], 2, GLES30.GL_FLOAT, false, 0, mSquareVertices );
+ GLES30.glVertexAttribPointer ( mTexCoordLocHandle[0], 2, GLES30.GL_FLOAT, false, 0, mSquareTextureCoordinates[0] );
+ GLES30.glUniformMatrix4fv( mMVPMtrxhandle[0], 1, false, mtrxProjectionAndView, 0);
+ GLES30.glEnableVertexAttribArray( mVerticesHandle[0] );
+ GLES30.glEnableVertexAttribArray ( mTexCoordLocHandle[0] );
+
+ //GLES30.glDrawElements( GLES30.GL_TRIANGLES, 6, GLES30.GL_UNSIGNED_SHORT, mSquareDrawIndices );
+ GLES30.glDrawArrays( GLES30.GL_TRIANGLE_STRIP, 0, 4 );
+
+ if ( offline ) {
+ int status = GLES30.glCheckFramebufferStatus( GLES30.GL_FRAMEBUFFER );
+ if ( status == GLES30.GL_FRAMEBUFFER_COMPLETE ) {
+ /// Debug
+ /// GLES30.glReadPixels( 0, 0, mFrameWidth, mFrameHeight, GLES30.GL_RGB, GLES30.GL_UNSIGNED_BYTE, scratchRGB );
+ /// Log.e( TAG, "RGB Buffer " + scratchRGB.get(1000) + " " + scratchRGB.get(1001) +
+ /// "handles " + mCamTexture.getInRGBFBO() + " " + mCamTexture.getInRGBTex() );
+ } else {
+ Log.e( TAG, "FBO status " + status + "error " + GLES30.glGetError() );
+ }
+ }
+
+ // Disable vertex array
+ GLES30.glDisableVertexAttribArray( mVerticesHandle[0] );
+ GLES30.glDisableVertexAttribArray( mTexCoordLocHandle[0] );
+ // Reset FBO
+ GLES30.glBindFramebuffer( GLES30.GL_FRAMEBUFFER, 0 );
+ GLES30.glBindTexture( GLES30.GL_TEXTURE_2D, 0 );
+ }
+
+ public void executeBlur( int level )
+ {
+ int viewPortScaleFactor = 1;
+ int texScaleFactor = 1;
+ float blurScaleFactor = 1.0f; // 2x->.5
+
+ switch ( blurType )
+ {
+ case BlurTypeGaussianPyramid:
+ viewPortScaleFactor = level + 1;
+ texScaleFactor = level;
+ break;
+ case BlurTypeGaussianDilated:
+ blurScaleFactor = 4.0f;
+ break;
+ case BlurTypeGaussianKernelSize:
+ break;
+ }
+
+ GLES30.glClear( GLES30.GL_COLOR_BUFFER_BIT );
+ //GLES30.glViewport( 0, 0, ( int )mFrameWidth/(level+1), ( int )mFrameHeight/(level+1) );
+ GLES30.glViewport( 0, 0, ( int )mFrameWidth/viewPortScaleFactor,
+ ( int )mFrameHeight/viewPortScaleFactor );
+
+ // Bind Mask texture to texturename
+ GLES30.glActiveTexture( GLES30.GL_TEXTURE0 );
+ // GLES30.glBindTexture( GLES30.GL_TEXTURE_2D, mCamTexture.getInRGBTex( 0 ) );
+ GLES30.glBindTexture( GLES30.GL_TEXTURE_2D, mCamTexture.getInRGBTex( level - 1 ) );
+ GLES30.glTexSubImage2D( GLES30.GL_TEXTURE_2D, 0, 0, 0,
+ mFrameWidth/texScaleFactor,
+ mFrameHeight/texScaleFactor,
+ GLES30.GL_RGB, GLES30.GL_UNSIGNED_BYTE, null );
+ GLES30.glUniform1i ( mInRGBHandle[level-1], 0 );
+
+ GLES30.glBindFramebuffer( GLES30.GL_FRAMEBUFFER, mCamTexture.getInRGBFBO( level ) );
+ GLES30.glFramebufferTexture2D( GLES30.GL_FRAMEBUFFER, GLES30.GL_COLOR_ATTACHMENT0,
+ GLES30.GL_TEXTURE_2D, mCamTexture.getInRGBTex( level ), 0 );
+
+ float xPixelOffset = blurScaleFactor/(float)mFrameWidth;
+ float yPixelOffset = blurScaleFactor/(float)mFrameHeight;
+ float mipLevel = (float)level;
+ GLES30.glUniform1f( mMipLevelUniform, mipLevel );
+ GLES30.glUniform1f( mXPixelOffsetUniform, xPixelOffset );
+ GLES30.glUniform1f( mYPixelOffsetUniform, yPixelOffset );
+
+ GLES30.glUseProgram( mBlurProgramHandle );
+
+ GLES30.glVertexAttribPointer( mVerticesHandle[2], 2, GLES30.GL_FLOAT, false, 0, mSquareVertices );
+ GLES30.glEnableVertexAttribArray( mVerticesHandle[2] );
+ GLES30.glVertexAttribPointer ( mTexCoordLocHandle[2], 2, GLES30.GL_FLOAT, false, 0, mSquareTextureCoordinates[0] );
+ GLES30.glEnableVertexAttribArray ( mTexCoordLocHandle[2] );
+
+ // GLES30.glDrawElements( GLES30.GL_TRIANGLES, 6, GLES30.GL_UNSIGNED_SHORT, mSquareDrawIndices );
+ GLES30.glDrawArrays( GLES30.GL_TRIANGLE_STRIP, 0, 4 );
+
+ // Disable vertex array
+ GLES30.glDisableVertexAttribArray( mVerticesHandle[2] );
+ GLES30.glDisableVertexAttribArray( mTexCoordLocHandle[2] );
+
+ // Reset FBO
+ GLES30.glBindFramebuffer( GLES30.GL_FRAMEBUFFER, 0 );
+ GLES30.glBindTexture( GLES30.GL_TEXTURE_2D, 0 );
+ }
+
+ public void executeBlend( ByteBuffer bufferMask, int level )
+ {
+ GLES30.glClear( GLES30.GL_COLOR_BUFFER_BIT /*| GLES30.GL_DEPTH_BUFFER_BIT*/ );
+ GLES30.glViewport( mScreenROIX, mScreenROIY, ( int )mScreenROIWidth, ( int )mScreenROIHeight );
+ //GLES30.glEnable( GLES30.GL_DEPTH_TEST );
+ GLES30.glUseProgram( mProgramHandle );
+
+ // Bind Mask texture to texturename
+ GLES30.glActiveTexture( GLES30.GL_TEXTURE0 );
+ GLES30.glBindTexture( GLES30.GL_TEXTURE_2D, mCamTexture.getInRGBTex( 0 ) );
+ GLES30.glTexSubImage2D( GLES30.GL_TEXTURE_2D, 0, 0, 0, mFrameWidth, mFrameHeight,
+ GLES30.GL_RGB, GLES30.GL_UNSIGNED_BYTE, null );
+ GLES30.glUniform1i ( mForegroundRGBHandle, 0 );
+
+ GLES30.glActiveTexture( GLES30.GL_TEXTURE1 );
+ GLES30.glBindTexture( GLES30.GL_TEXTURE_2D, mCamTexture.getInRGBTex(level));
+ //GLES30.glTexSubImage2D( GLES30.GL_TEXTURE_2D, 0, 0, 0, mFrameWidth/(level+1), mFrameHeight/(level+1),
+ GLES30.glTexSubImage2D( GLES30.GL_TEXTURE_2D, 0, 0, 0, mFrameWidth, mFrameHeight,
+ GLES30.GL_RGB, GLES30.GL_UNSIGNED_BYTE, null );
+ GLES30.glUniform1i ( mBackGroundRGBHandle, 1 );
+
+ GLES30.glActiveTexture( GLES30.GL_TEXTURE2 );
+ GLES30.glBindTexture( GLES30.GL_TEXTURE_2D, mCamTexture.getMaskTex() );
+ GLES30.glTexSubImage2D( GLES30.GL_TEXTURE_2D, 0, 0, 0, mMaskWidth, mMaskHeight,
+ GLES30.GL_LUMINANCE, GLES30.GL_UNSIGNED_BYTE, bufferMask );
+ GLES30.glUniform1i ( mMaskHandle, 2 );
+
+ GLES30.glVertexAttribPointer( mVerticesHandle[1], 2, GLES30.GL_FLOAT, false, 0, mSquareVertices );
+ GLES30.glEnableVertexAttribArray( mVerticesHandle[1] );
+ GLES30.glVertexAttribPointer ( mTexCoordLocHandle[1], 2, GLES30.GL_FLOAT, false, 0, mSquareTextureCoordinates[0] );
+ GLES30.glEnableVertexAttribArray ( mTexCoordLocHandle[1] );
+ GLES30.glUniformMatrix4fv( mMVPMtrxhandle[1], 1, false, mtrxProjectionAndView, 0 );
+ GLES30.glUniformMatrix3fv( mRotMtrxhandle, 1, false, mRotationMatrix, 0 );
+ GLES30.glUniformMatrix3fv( mSurfaceRotMtrxhandle, 1, false, mSurfaceRotationMatrix, 0 );
+ GLES30.glUniformMatrix2fv( mFlipMtrxhandle, 1, false, flipNone, 0 );
+
+ // GLES30.glDrawElements( GLES30.GL_TRIANGLES, 6, GLES30.GL_UNSIGNED_SHORT, mSquareDrawIndices );
+ GLES30.glDrawArrays( GLES30.GL_TRIANGLE_STRIP, 0, 4 );
+
+ // Disable vertex array
+ GLES30.glDisableVertexAttribArray( mVerticesHandle[1] );
+ GLES30.glDisableVertexAttribArray( mTexCoordLocHandle[1] );
+ }
+
+ @Override
+ public void onDrawFrame( GL10 unused )
+ {
+ if ( !mActive || mFrameQueue.size() == 0 ) {
+ return;
+ }
+
+ currentTime = System.currentTimeMillis();
+ long delta = currentTime - prevTime;
+ Log.d(TAG,"frame delta time = "+delta);
+ try {
+ if ( minFrameDelta > delta )
+ Thread.sleep( minFrameDelta - delta );
+ } catch ( InterruptedException e ) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ prevTime = System.currentTimeMillis();
+
+ if ( !mTexturesCreated && mMaskWidth > 0 && mMaskHeight > 0 ) {
+ Log.d( TAG, "onDrawFrame createTextures " + blurType );
+ mCamTexture.createTextures( mFrameWidth, mFrameHeight,
+ mMaskWidth, mMaskHeight, 8,
+ blurType );
+ mTexturesCreated = true;
+ } else if ( !mTexturesCreated ) {
+ // No op
+ return;
+ }
+
+ DPImage dpimage = mFrameQueue.get( 0 );
+ mFrameQueue.removeElementAt( 0 );
+ Plane[] planes = dpimage.mImage.getPlanes();
+ ByteBuffer bufferY = planes[0].getBuffer();
+ ByteBuffer bufferC = planes[2].getBuffer();
+
+ if ( dpimage.mMask == null) {
+ executeConverter( bufferY, bufferC, false );
+ Log.d( TAG, "onDrawFrame no processing" );
+ } else {
+ int mipLevel = (int)(( mBlurLevel * 8.0f )/100.0f);
+ if ( mipLevel >= 7 )
+ mipLevel = 7;// clamp
+ Log.d( TAG, "[DP_BUF_DBG] onDrawFrame frame " + dpimage.mSeqNumber + " mipLevel "
+ + mipLevel );
+ executeConverter( bufferY, bufferC, true );
+
+ for ( int lvl = 1; lvl <= mipLevel; ++lvl ) {
+ executeBlur( lvl );
+ }
+
+ // Set rotation
+ if ( dpimage.mOrientation >= 0 ) {
+ prepareRotationMatrix( dpimage.mOrientation );
+ }
+ executeBlend( dpimage.mMask, mipLevel );
+ }
+ if ( mActive ) {
+ mObserver.onRenderComplete( dpimage, false );
+ }
+ }
+
+ private native String getShaderByName(String type);
+}
diff --git a/src/com/android/camera/deepportrait/CamRenderShader.java b/src/com/android/camera/deepportrait/CamRenderShader.java
new file mode 100755
index 000000000..5b80ed919
--- /dev/null
+++ b/src/com/android/camera/deepportrait/CamRenderShader.java
@@ -0,0 +1,105 @@
+/*
+ * 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 com.android.camera.deepportrait;
+import android.opengl.GLES30;
+import android.util.Log;
+
+public class CamRenderShader
+{
+ public static final String TAG = "<dp><app><CamRenderShader>";
+
+ public static int compileShader( final int shaderType, final String shaderSource )
+ {
+ int shaderHandle = GLES30.glCreateShader( shaderType );
+
+ if ( shaderHandle != 0 )
+ {
+ // Pass in the shader source.
+ GLES30.glShaderSource( shaderHandle, shaderSource );
+
+ // Compile the shader.
+ GLES30.glCompileShader( shaderHandle );
+
+ // Get the compilation status.
+ final int[] compileStatus = new int[1];
+ GLES30.glGetShaderiv( shaderHandle, GLES30.GL_COMPILE_STATUS, compileStatus, 0 );
+
+ // If the compilation failed, delete the shader.
+ if ( compileStatus[0] == 0 )
+ {
+ Log.e( TAG, "Error compiling shader: " + GLES30.glGetShaderInfoLog( shaderHandle ) );
+ GLES30.glDeleteShader( shaderHandle );
+ shaderHandle = 0;
+ }
+ }
+
+ if ( shaderHandle == 0 )
+ {
+ throw new RuntimeException( "Error creating shader." );
+ }
+
+ return shaderHandle;
+ }
+
+ public static int createAndLinkProgram( final int vertexShaderHandle,
+ final int fragmentShaderHandle )
+ {
+ int programHandle = GLES30.glCreateProgram();
+
+ if ( programHandle != 0 ) {
+ // Bind the vertex shader to the program.
+ GLES30.glAttachShader( programHandle, vertexShaderHandle );
+
+ // Bind the fragment shaders to the program
+ GLES30.glAttachShader( programHandle, fragmentShaderHandle );
+
+ // Link the two shaders together into a program.
+ GLES30.glLinkProgram( programHandle );
+
+ // Get the link status.
+ final int[] linkStatus = new int[1];
+ GLES30.glGetProgramiv( programHandle, GLES30.GL_LINK_STATUS, linkStatus, 0 );
+
+ // If the link failed, delete the program.
+ if ( linkStatus[0] == 0 )
+ {
+ Log.e(TAG, "Error compiling program: " + GLES30.glGetProgramInfoLog(programHandle));
+ GLES30.glDeleteProgram(programHandle);
+ programHandle = 0;
+ }
+ }
+
+ if ( programHandle == 0 ) {
+ throw new RuntimeException("Error creating program.");
+ }
+
+ return programHandle;
+ }
+}
diff --git a/src/com/android/camera/deepportrait/CamRenderTexture.java b/src/com/android/camera/deepportrait/CamRenderTexture.java
new file mode 100755
index 000000000..c0b4108b3
--- /dev/null
+++ b/src/com/android/camera/deepportrait/CamRenderTexture.java
@@ -0,0 +1,114 @@
+/*
+ * 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 com.android.camera.deepportrait;
+
+import java.nio.ByteBuffer;
+import android.opengl.GLES30;
+
+public class CamRenderTexture
+{
+ int[] mTextureHandle;
+ int[] mFBO;
+ int[] mRBO;
+ public enum BlurType
+ {
+ BlurTypeGaussianDilated,
+ BlurTypeGaussianPyramid,
+ BlurTypeGaussianKernelSize,
+ }
+
+ public int getInYTex() { return mTextureHandle[0]; }
+ public int getInCTex() { return mTextureHandle[1]; }
+ public int getMaskTex() { return mTextureHandle[2]; }
+ public int getInRGBTex( int level ) { return mTextureHandle[3 + level]; }
+ public int getInRGBFBO( int level ) { return mFBO[level]; }
+ public int getInRGBRBO( int level ) { return mRBO[level]; }
+
+ public void createTextures( int width, int height, int maskW, int maskH,
+ int levels, BlurType blurType )
+ {
+ mTextureHandle = new int[3 + levels];
+ mFBO = new int[levels];
+ mRBO = new int[levels];
+ GLES30.glGenTextures( mTextureHandle.length, mTextureHandle, 0 );
+
+ // Input Luma
+ GLES30.glBindTexture( GLES30.GL_TEXTURE_2D, mTextureHandle[0] );
+ GLES30.glTexParameteri( GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_MIN_FILTER, GLES30.GL_LINEAR );
+ GLES30.glTexParameteri( GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_MAG_FILTER, GLES30.GL_LINEAR );
+ GLES30.glTexParameteri(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_WRAP_S, GLES30.GL_CLAMP_TO_EDGE);
+ GLES30.glTexParameteri(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_WRAP_T, GLES30.GL_CLAMP_TO_EDGE);
+ GLES30.glTexImage2D( GLES30.GL_TEXTURE_2D, 0, GLES30.GL_LUMINANCE, width, height, 0,
+ GLES30.GL_LUMINANCE, GLES30.GL_UNSIGNED_BYTE, null );
+
+ // Input chroma
+ GLES30.glBindTexture( GLES30.GL_TEXTURE_2D, mTextureHandle[1] );
+ GLES30.glTexParameteri( GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_MIN_FILTER, GLES30.GL_LINEAR );
+ GLES30.glTexParameteri( GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_MAG_FILTER, GLES30.GL_LINEAR );
+ GLES30.glTexParameteri(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_WRAP_S, GLES30.GL_CLAMP_TO_EDGE);
+ GLES30.glTexParameteri(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_WRAP_T, GLES30.GL_CLAMP_TO_EDGE);
+ GLES30.glTexImage2D( GLES30.GL_TEXTURE_2D, 0, GLES30.GL_LUMINANCE_ALPHA, width/2, height/2, 0,
+ GLES30.GL_LUMINANCE_ALPHA, GLES30.GL_UNSIGNED_BYTE, null );
+
+ // mask
+ GLES30.glBindTexture( GLES30.GL_TEXTURE_2D, mTextureHandle[2] );
+ GLES30.glTexParameteri( GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_MIN_FILTER, GLES30.GL_NEAREST );
+ GLES30.glTexParameteri( GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_MAG_FILTER, GLES30.GL_NEAREST );
+ GLES30.glTexImage2D( GLES30.GL_TEXTURE_2D, 0, GLES30.GL_LUMINANCE, maskW, maskH, 0,
+ GLES30.GL_LUMINANCE , GLES30.GL_UNSIGNED_BYTE, null );
+
+ // Input RGB
+ GLES30.glGenFramebuffers( levels, mFBO, 0 );
+
+ for ( int i = 0; i < levels; ++i )
+ {
+ int scaleFactor = ( blurType == BlurType.BlurTypeGaussianPyramid ) ? i + 1 : 1;
+ GLES30.glBindTexture( GLES30.GL_TEXTURE_2D, mTextureHandle[3 + i] );
+ GLES30.glTexParameteri( GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_MIN_FILTER, GLES30.GL_LINEAR );
+ GLES30.glTexParameteri( GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_MAG_FILTER, GLES30.GL_LINEAR );
+ GLES30.glTexParameteri(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_WRAP_S, GLES30.GL_CLAMP_TO_EDGE);
+ GLES30.glTexParameteri(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_WRAP_T, GLES30.GL_CLAMP_TO_EDGE);
+ GLES30.glTexImage2D( GLES30.GL_TEXTURE_2D, 0, GLES30.GL_RGB,
+ width/scaleFactor, height/scaleFactor, 0,
+ GLES30.GL_RGB , GLES30.GL_UNSIGNED_BYTE, null );
+ }
+ //ToDo: move to render buffers
+ // GLES30.glGenRenderbuffers( 1, mRBO, 0 );
+ // GLES30.glBindRenderbuffer( GLES30.GL_RENDERBUFFER, mRBO[0]);
+ // GLES30.glRenderbufferStorage( GLES30.GL_RENDERBUFFER, GLES30.GL_RGB, width, height );
+ }
+
+ public void deleteTextures()
+ {
+ GLES30.glDeleteTextures( mTextureHandle.length, mTextureHandle, 0 );
+ GLES30.glDeleteFramebuffers ( mFBO.length, mFBO, 0 );
+ // GLES30.glDeleteRenderbuffers( mRBO.length, mRBO, 0 );
+ }
+}
diff --git a/src/com/android/camera/deepportrait/DPImage.java b/src/com/android/camera/deepportrait/DPImage.java
new file mode 100755
index 000000000..381270682
--- /dev/null
+++ b/src/com/android/camera/deepportrait/DPImage.java
@@ -0,0 +1,57 @@
+/*
+ * 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 com.android.camera.deepportrait;
+import android.media.Image;
+import android.media.Image.Plane;
+import java.nio.ByteBuffer;
+
+public class DPImage
+{
+ public Image mImage;
+ public ByteBuffer mMask;
+ public int mMaskWidth = 0;
+ public int mMaskHeight = 0;
+ public int mSeqNumber = 0;
+ public int mOrientation = 0;
+ public DPImage( Image aImage, ByteBuffer aMask, int orientation)
+ {
+ mImage = aImage;
+ mMask= aMask;
+ mOrientation = orientation;
+ }
+
+ public DPImage(Image aImage, int orientation)
+ {
+ mImage = aImage;
+ mMask = null;
+ mOrientation = orientation;
+ }
+}
diff --git a/src/com/android/camera/deepportrait/GLCameraPreview.java b/src/com/android/camera/deepportrait/GLCameraPreview.java
new file mode 100755
index 000000000..7d62faebf
--- /dev/null
+++ b/src/com/android/camera/deepportrait/GLCameraPreview.java
@@ -0,0 +1,343 @@
+/*
+ * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ * Not a Contribution
+ *
+ * Copyright 2008-2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.camera.deepportrait;
+
+import android.app.Activity;
+import android.content.Context;
+import android.opengl.GLSurfaceView;
+import android.view.SurfaceHolder;
+
+import javax.microedition.khronos.egl.EGL10;
+import javax.microedition.khronos.egl.EGLConfig;
+import javax.microedition.khronos.egl.EGLContext;
+import javax.microedition.khronos.egl.EGLDisplay;
+import javax.microedition.khronos.opengles.GL10;
+import android.opengl.GLES30;
+import android.util.Log;
+
+public class GLCameraPreview extends GLSurfaceView
+{
+ private CamGLRenderer mRenderer;
+ private CamGLRenderObserver mObserver;
+ public static String TAG = "<dp><app><GLSurfaceView>";
+
+ private static class ContextFactory implements EGLContextFactory
+ {
+ private static final int EGL_CONTEXT_CLIENT_VERSION = 0x3098;
+ public static final int EGL_CONTEXT_PRIORITY_LEVEL_IMG = 0x3100;
+ public static final int EGL_CONTEXT_PRIORITY_HIGH_IMG = 0x3101;
+ public static final int EGL_CONTEXT_PRIORITY_MED_IMG = 0x3102;
+
+ public EGLContext createContext(EGL10 egl, EGLDisplay display,
+ EGLConfig eglConfig)
+ {
+ Log.w(TAG, "creating OpenGL ES 3.0 context");
+ checkEglError("Before eglCreateContext", egl);
+ int[] attrib_list = { EGL_CONTEXT_CLIENT_VERSION, 3,
+ EGL_CONTEXT_PRIORITY_LEVEL_IMG, EGL_CONTEXT_PRIORITY_MED_IMG,
+ EGL10.EGL_NONE, EGL10.EGL_NONE };
+ EGLContext context = egl.eglCreateContext(display, eglConfig,
+ EGL10.EGL_NO_CONTEXT, attrib_list);
+ checkEglError("After eglCreateContext", egl);
+ return context;
+ }
+
+ public void destroyContext(EGL10 egl, EGLDisplay display, EGLContext context)
+ {
+ egl.eglDestroyContext(display, context);
+ }
+ }
+
+ private static void checkEglError(String prompt, EGL10 egl)
+ {
+ int error;
+ while ((error = egl.eglGetError()) != EGL10.EGL_SUCCESS)
+ {
+ Log.e(TAG, String.format("%s: EGL error: 0x%x", prompt, error));
+ }
+ }
+
+ private static class ConfigChooser implements EGLConfigChooser
+ {
+
+ public ConfigChooser(int r, int g, int b, int a, int depth, int stencil)
+ {
+ mRedSize = r;
+ mGreenSize = g;
+ mBlueSize = b;
+ mAlphaSize = a;
+ mDepthSize = depth;
+ mStencilSize = stencil;
+ }
+
+ /*
+ * This EGL config specification is used to specify 2.0 rendering. We
+ * use a minimum size of 4 bits for red/green/blue, but will perform
+ * actual matching in chooseConfig() below.
+ */
+ private static int EGL_OPENGL_ES2_BIT = 4;
+ private static int[] s_configAttribs2 = { EGL10.EGL_RED_SIZE, 4,
+ EGL10.EGL_GREEN_SIZE, 4, EGL10.EGL_BLUE_SIZE, 4,
+ EGL10.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, EGL10.EGL_NONE };
+
+ public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display)
+ {
+
+ /*
+ * Get the number of minimally matching EGL configurations
+ */
+ int[] num_config = new int[1];
+ egl.eglChooseConfig(display, s_configAttribs2, null, 0, num_config);
+
+ int numConfigs = num_config[0];
+
+ if (numConfigs <= 0)
+ {
+ throw new IllegalArgumentException(
+ "No configs match configSpec");
+ }
+
+ /*
+ * Allocate then read the array of minimally matching EGL configs
+ */
+ EGLConfig[] configs = new EGLConfig[numConfigs];
+ egl.eglChooseConfig(display, s_configAttribs2, configs, numConfigs,
+ num_config);
+
+ printConfigs(egl, display, configs);
+ /*
+ * Now return the "best" one
+ */
+ return chooseConfig(egl, display, configs);
+ }
+
+ public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display,
+ EGLConfig[] configs)
+ {
+ for (EGLConfig config : configs)
+ {
+ int d = findConfigAttrib(egl, display, config,
+ EGL10.EGL_DEPTH_SIZE, 0);
+ int s = findConfigAttrib(egl, display, config,
+ EGL10.EGL_STENCIL_SIZE, 0);
+
+ // We need at least mDepthSize and mStencilSize bits
+ if (d < mDepthSize || s < mStencilSize)
+ continue;
+
+ // We want an *exact* match for red/green/blue/alpha
+ int r = findConfigAttrib(egl, display, config,
+ EGL10.EGL_RED_SIZE, 0);
+ int g = findConfigAttrib(egl, display, config,
+ EGL10.EGL_GREEN_SIZE, 0);
+ int b = findConfigAttrib(egl, display, config,
+ EGL10.EGL_BLUE_SIZE, 0);
+ int a = findConfigAttrib(egl, display, config,
+ EGL10.EGL_ALPHA_SIZE, 0);
+
+ if (r == mRedSize && g == mGreenSize && b == mBlueSize
+ && a == mAlphaSize)
+ return config;
+ }
+ return null;
+ }
+
+ private int findConfigAttrib(EGL10 egl, EGLDisplay display,
+ EGLConfig config, int attribute, int defaultValue)
+ {
+
+ if (egl.eglGetConfigAttrib(display, config, attribute, mValue))
+ {
+ return mValue[0];
+ }
+ return defaultValue;
+ }
+
+ private void printConfigs(EGL10 egl, EGLDisplay display,
+ EGLConfig[] configs)
+ {
+ int numConfigs = configs.length;
+ Log.w(TAG, String.format("%d configurations", numConfigs));
+ for (int i = 0; i < numConfigs; i++)
+ {
+ Log.w(TAG, String.format("Configuration %d:\n", i));
+ printConfig(egl, display, configs[i]);
+ }
+ }
+
+ private void printConfig(EGL10 egl, EGLDisplay display, EGLConfig config)
+ {
+ int[] attributes = { EGL10.EGL_BUFFER_SIZE, EGL10.EGL_ALPHA_SIZE,
+ EGL10.EGL_BLUE_SIZE,
+ EGL10.EGL_GREEN_SIZE,
+ EGL10.EGL_RED_SIZE,
+ EGL10.EGL_DEPTH_SIZE,
+ EGL10.EGL_STENCIL_SIZE,
+ EGL10.EGL_CONFIG_CAVEAT,
+ EGL10.EGL_CONFIG_ID,
+ EGL10.EGL_LEVEL,
+ EGL10.EGL_MAX_PBUFFER_HEIGHT,
+ EGL10.EGL_MAX_PBUFFER_PIXELS,
+ EGL10.EGL_MAX_PBUFFER_WIDTH,
+ EGL10.EGL_NATIVE_RENDERABLE,
+ EGL10.EGL_NATIVE_VISUAL_ID,
+ EGL10.EGL_NATIVE_VISUAL_TYPE,
+ 0x3030, // EGL10.EGL_PRESERVED_RESOURCES,
+ EGL10.EGL_SAMPLES,
+ EGL10.EGL_SAMPLE_BUFFERS,
+ EGL10.EGL_SURFACE_TYPE,
+ EGL10.EGL_TRANSPARENT_TYPE,
+ EGL10.EGL_TRANSPARENT_RED_VALUE,
+ EGL10.EGL_TRANSPARENT_GREEN_VALUE,
+ EGL10.EGL_TRANSPARENT_BLUE_VALUE,
+ 0x3039, // EGL10.EGL_BIND_TO_TEXTURE_RGB,
+ 0x303A, // EGL10.EGL_BIND_TO_TEXTURE_RGBA,
+ 0x303B, // EGL10.EGL_MIN_SWAP_INTERVAL,
+ 0x303C, // EGL10.EGL_MAX_SWAP_INTERVAL,
+ EGL10.EGL_LUMINANCE_SIZE, EGL10.EGL_ALPHA_MASK_SIZE,
+ EGL10.EGL_COLOR_BUFFER_TYPE, EGL10.EGL_RENDERABLE_TYPE,
+ 0x3042 // EGL10.EGL_CONFORMANT
+ };
+ String[] names = { "EGL_BUFFER_SIZE", "EGL_ALPHA_SIZE",
+ "EGL_BLUE_SIZE", "EGL_GREEN_SIZE", "EGL_RED_SIZE",
+ "EGL_DEPTH_SIZE", "EGL_STENCIL_SIZE", "EGL_CONFIG_CAVEAT",
+ "EGL_CONFIG_ID", "EGL_LEVEL", "EGL_MAX_PBUFFER_HEIGHT",
+ "EGL_MAX_PBUFFER_PIXELS", "EGL_MAX_PBUFFER_WIDTH",
+ "EGL_NATIVE_RENDERABLE", "EGL_NATIVE_VISUAL_ID",
+ "EGL_NATIVE_VISUAL_TYPE", "EGL_PRESERVED_RESOURCES",
+ "EGL_SAMPLES", "EGL_SAMPLE_BUFFERS", "EGL_SURFACE_TYPE",
+ "EGL_TRANSPARENT_TYPE", "EGL_TRANSPARENT_RED_VALUE",
+ "EGL_TRANSPARENT_GREEN_VALUE",
+ "EGL_TRANSPARENT_BLUE_VALUE", "EGL_BIND_TO_TEXTURE_RGB",
+ "EGL_BIND_TO_TEXTURE_RGBA", "EGL_MIN_SWAP_INTERVAL",
+ "EGL_MAX_SWAP_INTERVAL", "EGL_LUMINANCE_SIZE",
+ "EGL_ALPHA_MASK_SIZE", "EGL_COLOR_BUFFER_TYPE",
+ "EGL_RENDERABLE_TYPE", "EGL_CONFORMANT" };
+ int[] value = new int[1];
+ for (int i = 0; i < attributes.length; i++)
+ {
+ int attribute = attributes[i];
+ String name = names[i];
+ if (egl.eglGetConfigAttrib(display, config, attribute, value))
+ {
+ Log.w(TAG, String.format(" %s: %d\n", name, value[0]));
+ } else
+ {
+ // Log.w(TAG, String.format(" %s: failed\n", name));
+ while (egl.eglGetError() != EGL10.EGL_SUCCESS)
+ ;
+ }
+ }
+ }
+
+ // Subclasses can adjust these values:
+ protected int mRedSize;
+ protected int mGreenSize;
+ protected int mBlueSize;
+ protected int mAlphaSize;
+ protected int mDepthSize;
+ protected int mStencilSize;
+ private int[] mValue = new int[1];
+ }
+
+ public GLCameraPreview( Context context, int textureWidth,
+ int textureHeight, CamGLRenderObserver observer )
+ {
+ super( context );
+ mObserver = observer;
+ // Create an OpenGL ES 3.0 context.
+ setEGLContextClientVersion( 3 );
+
+ /*
+ * Setup the context factory for 2.0 rendering. See ContextFactory class
+ * definition below
+ */
+ setEGLContextFactory(new ContextFactory());
+
+ /*
+ * We need to choose an EGLConfig that matches the format of our surface
+ * exactly. This is going to be done in our custom config chooser. See
+ * ConfigChooser class definition below.
+ */
+ boolean translucent = false;
+ int depth = 0;
+ int stencil = 0;
+ //setEGLConfigChooser(translucent ? new ConfigChooser(8, 8, 8, 8, depth,
+ // stencil) : new ConfigChooser(5, 6, 5, 0, depth, stencil));
+
+ // Set the Renderer for drawing on the GLSurfaceView
+ mRenderer = new CamGLRenderer( context, textureWidth, textureHeight, observer, this );
+ setRenderer( mRenderer );
+
+ // Render the view only when there is a change in the drawing data
+ setRenderMode( GLSurfaceView.RENDERMODE_WHEN_DIRTY );
+ // setRenderMode( GLSurfaceView.RENDERMODE_CONTINUOUSLY );
+
+ mRenderer.open();
+ }
+
+ @Override
+ public void onPause()
+ {
+ super.onPause();
+ mRenderer.onPause();
+ }
+
+ @Override
+ public void onResume()
+ {
+ super.onResume();
+ mRenderer.onResume();
+ }
+
+ @Override
+ public void surfaceChanged( SurfaceHolder holder, int format, int w, int h )
+ {
+ super.surfaceChanged( holder, format, w, h );
+ }
+
+ @Override
+ public void surfaceCreated( SurfaceHolder holder )
+ {
+ super.surfaceCreated( holder );
+ mObserver.onRenderSurfaceCreated();
+ if (mRenderer != null) {
+ mRenderer.onResume();
+ }
+ }
+
+ @Override
+ public void surfaceDestroyed( SurfaceHolder holder )
+ {
+ super.surfaceDestroyed( holder );
+ if ( mRenderer != null ) {
+ mObserver.onRenderSurfaceDestroyed();
+ Log.e( TAG, " surfaceDestroyed Close renderer" );
+ mRenderer.onPause();
+ mRenderer.close();
+ mRenderer = null;
+ }
+ }
+
+ public CamGLRenderer getRendererInstance()
+ {
+ return mRenderer;
+ }
+}
diff --git a/src/com/android/camera/imageprocessor/FrameProcessor.java b/src/com/android/camera/imageprocessor/FrameProcessor.java
index 2e7ded169..4eaf7f7ad 100755
--- a/src/com/android/camera/imageprocessor/FrameProcessor.java
+++ b/src/com/android/camera/imageprocessor/FrameProcessor.java
@@ -46,8 +46,12 @@ import android.view.Surface;
import android.widget.Toast;
import com.android.camera.CaptureModule;
+import com.android.camera.PhotoModule;
import com.android.camera.SettingsManager;
+import com.android.camera.deepportrait.DPImage;
+import com.android.camera.deepportrait.GLCameraPreview;
import com.android.camera.imageprocessor.filter.BeautificationFilter;
+import com.android.camera.imageprocessor.filter.DeepPortraitFilter;
import com.android.camera.imageprocessor.filter.ImageFilter;
import com.android.camera.imageprocessor.filter.TrackingFocusFrameListener;
import com.android.camera.ui.RotateTextToast;
@@ -90,8 +94,11 @@ public class FrameProcessor {
public static final int FILTER_NONE = 0;
public static final int FILTER_MAKEUP = 1;
public static final int LISTENER_TRACKING_FOCUS = 2;
+ public static final int FILTER_DEEP_PORTRAIT = 3;
private CaptureModule mModule;
private boolean mIsVideoOn = false;
+ private boolean mIsDeepPortrait = false;
+ private DeepPortraitFilter mDeepPortraitFilter = null;
public FrameProcessor(Activity activity, CaptureModule module) {
mActivity = activity;
@@ -101,14 +108,14 @@ public class FrameProcessor {
mRs = RenderScript.create(mActivity);
mRsYuvToRGB = new ScriptC_YuvToRgb(mRs);
- mRsRotator = new ScriptC_rotator(mRs);
+ mRsRotator = new ScriptC_rotator(mRs);
}
private void init(Size previewDim) {
mIsActive = true;
mSize = previewDim;
synchronized (mAllocationLock) {
- mInputImageReader = ImageReader.newInstance(mSize.getWidth(), mSize.getHeight(), ImageFormat.YUV_420_888, 8);
+ mInputImageReader = ImageReader.newInstance(mSize.getWidth(), mSize.getHeight(), ImageFormat.YUV_420_888, 12);
Type.Builder rgbTypeBuilder = new Type.Builder(mRs, Element.RGBA_8888(mRs));
rgbTypeBuilder.setX(mSize.getHeight());
@@ -190,12 +197,29 @@ public class FrameProcessor {
public void onOpen(ArrayList<Integer> filterIds, final Size size) {
cleanFilterSet();
+ boolean hasDeepportraitFilter = false;
if (filterIds != null) {
for (Integer i : filterIds) {
addFilter(i.intValue());
+ if (i == FILTER_DEEP_PORTRAIT) {
+ hasDeepportraitFilter = true;
+ }
}
}
- if(isFrameFilterEnabled() || isFrameListnerEnabled()) {
+
+ mIsDeepPortrait = hasDeepportraitFilter;
+ if (mIsDeepPortrait && mPreviewFilters.size() != 0) {
+ mDeepPortraitFilter =
+ (DeepPortraitFilter)mPreviewFilters.get(0);
+ mDeepPortraitFilter.init(size.getWidth(),size.getHeight(),0,0);
+ if (!mDeepPortraitFilter.getDPInitialized())
+ Toast.makeText(mActivity, "Deepportrait init failed",
+ Toast.LENGTH_LONG).show();
+ } else {
+ mDeepPortraitFilter = null;
+ }
+
+ if(isFrameFilterEnabled() || isFrameListnerEnabled() || mIsDeepPortrait) {
init(size);
}
}
@@ -206,6 +230,8 @@ public class FrameProcessor {
filter = new BeautificationFilter(mModule);
} else if (filterId == LISTENER_TRACKING_FOCUS) {
filter = new TrackingFocusFrameListener(mModule);
+ } else if (filterId == FILTER_DEEP_PORTRAIT) {
+ filter = new DeepPortraitFilter(mModule,mModule.getCamGLRender());
}
if (filter != null && filter.isSupported()) {
@@ -292,6 +318,10 @@ public class FrameProcessor {
public List<Surface> getInputSurfaces() {
List<Surface> surfaces = new ArrayList<Surface>();
+ if (mIsDeepPortrait) {
+ surfaces.add(getReaderSurface());
+ return surfaces;
+ }
if (mPreviewFilters.size() == 0 && mFinalFilters.size() == 0) {
surfaces.add(mSurfaceAsItIs);
if (mIsVideoOn) {
@@ -390,6 +420,20 @@ public class FrameProcessor {
image.close();
return;
}
+ if (mIsDeepPortrait) {
+ //render to GLSurfaceView directly
+ GLCameraPreview preview = mModule.getGLCameraPreview();
+ if (mDeepPortraitFilter != null && mDeepPortraitFilter.getDPInitialized()
+ && preview != null) {
+ DPImage DpImage = new DPImage(image,0);
+ mDeepPortraitFilter.addImage(null,null,1,DpImage);
+ preview.getRendererInstance().sendFrame(DpImage);
+ preview.requestRender();
+ } else {
+ image.close();
+ }
+ return;
+ }
mIsAllocationEverUsed = true;
ByteBuffer bY = image.getPlanes()[0].getBuffer();
ByteBuffer bVU = image.getPlanes()[2].getBuffer();
@@ -411,7 +455,7 @@ public class FrameProcessor {
filter.init(mSize.getWidth(), mSize.getHeight(), stride, stride);
if (filter instanceof BeautificationFilter) {
filter.addImage(bY, bVU, 0, new Boolean(false));
- } else {
+ } else{
filter.addImage(bY, bVU, 0, new Boolean(true));
}
needToFeedSurface = true;
diff --git a/src/com/android/camera/imageprocessor/PostProcessor.java b/src/com/android/camera/imageprocessor/PostProcessor.java
index 72a92b4b3..c227f32b2 100644..100755
--- a/src/com/android/camera/imageprocessor/PostProcessor.java
+++ b/src/com/android/camera/imageprocessor/PostProcessor.java
@@ -30,6 +30,8 @@ package com.android.camera.imageprocessor;
import android.content.ContentResolver;
import android.content.Context;
+import android.content.SharedPreferences;
+import android.graphics.Bitmap;
import android.graphics.ImageFormat;
import android.graphics.Rect;
import android.graphics.YuvImage;
@@ -50,6 +52,7 @@ import android.media.ImageWriter;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
+import android.preference.PreferenceManager;
import android.util.Log;
import android.widget.Toast;
@@ -59,11 +62,13 @@ import com.android.camera.Exif;
import com.android.camera.MediaSaveService;
import com.android.camera.PhotoModule;
import com.android.camera.SettingsManager;
+import com.android.camera.deepportrait.DPImage;
import com.android.camera.exif.ExifInterface;
import com.android.camera.exif.Rational;
import com.android.camera.imageprocessor.filter.BestpictureFilter;
import com.android.camera.imageprocessor.filter.BlurbusterFilter;
import com.android.camera.imageprocessor.filter.ChromaflashFilter;
+import com.android.camera.imageprocessor.filter.DeepPortraitFilter;
import com.android.camera.imageprocessor.filter.OptizoomFilter;
import com.android.camera.imageprocessor.filter.SharpshooterFilter;
import com.android.camera.imageprocessor.filter.StillmoreFilter;
@@ -148,6 +153,7 @@ public class PostProcessor{
private LinkedList<ZSLQueue.ImageItem> mFallOffImages = new LinkedList<ZSLQueue.ImageItem>();
private int mPendingContinuousRequestCount = 0;
public int mMaxRequiredImageNum;
+ private boolean mIsDeepPortrait = false;
public int getMaxRequiredImageNum() {
return mMaxRequiredImageNum;
@@ -439,6 +445,12 @@ public class PostProcessor{
mZSLReprocessImageReader = ImageReader.newInstance(pictureSize.getWidth(), pictureSize.getHeight(), ImageFormat.JPEG, mMaxRequiredImageNum);
mZSLReprocessImageReader.setOnImageAvailableListener(processedImageAvailableListener, mHandler);
}
+ if (mIsDeepPortrait) {
+ ImageFilter imageFilter = mController.getFrameFilters().get(0);
+ DeepPortraitFilter deepPortraitFilter =
+ (DeepPortraitFilter) imageFilter;
+ deepPortraitFilter.initSnapshot(pictureSize.getWidth(),pictureSize.getHeight());
+ }
}
public boolean takeZSLPicture() {
@@ -678,9 +690,10 @@ public class PostProcessor{
public void onOpen(int postFilterId, boolean isFlashModeOn, boolean isTrackingFocusOn,
boolean isMakeupOn, boolean isSelfieMirrorOn, boolean isSaveRaw,
- boolean isSupportedQcfa) {
+ boolean isSupportedQcfa, boolean isDeepPortrait) {
mImageHandlerTask = new ImageHandlerTask();
mSaveRaw = isSaveRaw;
+ mIsDeepPortrait = isDeepPortrait;
if(setFilter(postFilterId) || isFlashModeOn || isTrackingFocusOn || isMakeupOn || isSelfieMirrorOn
|| PersistUtil.getCameraZSLDisabled()
|| !SettingsManager.getInstance().isZSLInAppEnabled()
@@ -690,7 +703,7 @@ public class PostProcessor{
|| "18".equals(SettingsManager.getInstance().getValue(
SettingsManager.KEY_SCENE_MODE))
|| mController.getCameraMode() == CaptureModule.DUAL_MODE
- || isSupportedQcfa) {
+ || isSupportedQcfa || isDeepPortrait) {
mUseZSL = false;
} else {
mUseZSL = true;
@@ -949,6 +962,17 @@ public class PostProcessor{
}
mOrientation = CameraUtil.getJpegRotation(mController.getMainCameraId(), mController.getDisplayOrientation());
}
+ if (mIsDeepPortrait) {
+ ImageFilter imageFilter = mController.getFrameFilters().get(0);
+ DeepPortraitFilter deepPortraitFilter =
+ (DeepPortraitFilter) imageFilter;
+ if (!deepPortraitFilter.getDPStillInit()) {
+ mStatus = STATUS.BUSY;
+ if(mWatchdog != null) {
+ mWatchdog.startMonitor();
+ }
+ }
+ }
if(mFilter != null && mCurrentNumImage >= mFilter.getNumRequiredImage()) {
return;
}
@@ -967,10 +991,78 @@ public class PostProcessor{
ByteBuffer vuBuf = image.getPlanes()[2].getBuffer();
if(mFilter == null) {
- mDefaultResultImage = new ImageFilter.ResultImage(ByteBuffer.allocateDirect(mStride * mHeight*3/2),
- new Rect(0, 0, mWidth, mHeight), mWidth, mHeight, mStride);
- yBuf.get(mDefaultResultImage.outBuffer.array(), 0, yBuf.remaining());
- vuBuf.get(mDefaultResultImage.outBuffer.array(), mStride*mHeight, vuBuf.remaining());
+ if (mIsDeepPortrait) {
+ ImageFilter imageFilter = mController.getFrameFilters().get(0);
+ DeepPortraitFilter deepPortraitFilter =
+ (DeepPortraitFilter) imageFilter;
+ DPImage dpImage = new DPImage(image,0);
+ long current = System.currentTimeMillis();
+ deepPortraitFilter.addImage(null,null,0,dpImage);
+ if (DEBUG_DUMP_FILTER_IMG) {
+ ImageFilter.ResultImage debugResultImage = new
+ ImageFilter.ResultImage(ByteBuffer.allocateDirect(
+ mStride * mHeight * 3 / 2), new Rect(0, 0, mWidth,
+ mHeight), mWidth, mHeight, mStride);
+ yBuf.get(debugResultImage.outBuffer.array(), 0, yBuf.remaining());
+ vuBuf.get(debugResultImage.outBuffer.array(), mStride * mHeight,
+ vuBuf.remaining());
+ yBuf.rewind();
+ vuBuf.rewind();
+
+ byte[] bytes = nv21ToJpeg(debugResultImage, mOrientation, null);
+ mActivity.getMediaSaveService().addImage(
+ bytes, "Debug_beforeApplyingFilter" + numImage, 0L, null,
+ debugResultImage.outRoi.width(),
+ debugResultImage.outRoi.height(),
+ mOrientation, null, mController.getMediaSavedListener(),
+ mActivity.getContentResolver(), "jpeg");
+
+ if (dpImage.mMask != null) {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ Bitmap mask = DeepPortraitFilter.DpMaskToImage(
+ dpImage.mMask, dpImage.mMaskWidth,dpImage.mMaskHeight);
+ mask.compress(Bitmap.CompressFormat.JPEG, 75, baos);
+ byte[] data = baos.toByteArray();
+ mActivity.getMediaSaveService().addImage(
+ data, "DPmask" + System.currentTimeMillis(), 0L, null,
+ dpImage.mMaskWidth,
+ dpImage.mMaskHeight,
+ mOrientation, null, mController.getMediaSavedListener(),
+ mActivity.getContentResolver(), "jpeg");
+ }
+ }
+ if (dpImage.mMask == null) {
+ Log.d(TAG,"can't generate deepportrait mask");
+ mDefaultResultImage = new ImageFilter.ResultImage(
+ ByteBuffer.allocateDirect(mStride * mHeight*3/2),
+ new Rect(0, 0, mWidth, mHeight), mWidth, mHeight, mStride);
+ yBuf.get(mDefaultResultImage.outBuffer.array(), 0, yBuf.remaining());
+ vuBuf.get(mDefaultResultImage.outBuffer.array(), mStride*mHeight, vuBuf.remaining());
+ } else {
+ ByteBuffer dstY = ByteBuffer.allocateDirect(yBuf.capacity());
+ ByteBuffer dstVU = ByteBuffer.allocateDirect(vuBuf.capacity());
+ final SharedPreferences prefs =
+ PreferenceManager.getDefaultSharedPreferences(mActivity);
+ int level = prefs.getInt(SettingsManager.KEY_DEEPPORTRAIT_VALUE
+ ,50);
+ deepPortraitFilter.renderDeepportraitImage(
+ dpImage,dstY,dstVU,0, level/100f);
+ Log.d(TAG,"process Dp snapshot cost time "+ (System.currentTimeMillis() - current));
+ mDefaultResultImage = new ImageFilter.ResultImage(
+ ByteBuffer.allocateDirect(mStride * mHeight*3/2),
+ new Rect(0, 0, mWidth, mHeight), mWidth, mHeight, mStride);
+ dstY.get(mDefaultResultImage.outBuffer.array(), 0,
+ dstY.remaining());
+ dstVU.get(mDefaultResultImage.outBuffer.array(), mStride*mHeight,
+ dstVU.remaining());
+ }
+ } else {
+ mDefaultResultImage = new ImageFilter.ResultImage(
+ ByteBuffer.allocateDirect(mStride * mHeight*3/2),
+ new Rect(0, 0, mWidth, mHeight), mWidth, mHeight, mStride);
+ yBuf.get(mDefaultResultImage.outBuffer.array(), 0, yBuf.remaining());
+ vuBuf.get(mDefaultResultImage.outBuffer.array(), mStride*mHeight, vuBuf.remaining());
+ }
image.close();
} else {
if (DEBUG_DUMP_FILTER_IMG) {
@@ -1070,9 +1162,12 @@ public class PostProcessor{
}
if(resultImage != null) {
//Start processing FrameProcessor filter as well
- for (ImageFilter filter : mController.getFrameFilters()) {
- filter.init(resultImage.width, resultImage.height, resultImage.stride, resultImage.stride);
- filter.addImage(resultImage.outBuffer, null, 0, new Boolean(false));
+ if (!mIsDeepPortrait) {
+ for (ImageFilter filter : mController.getFrameFilters()) {
+ filter.init(resultImage.width, resultImage.height,
+ resultImage.stride, resultImage.stride);
+ filter.addImage(resultImage.outBuffer, null, 0, new Boolean(false));
+ }
}
if(isSelfieMirrorOn() && !mController.isBackCamera()) {
@@ -1194,7 +1289,7 @@ public class PostProcessor{
}
};
- private byte[] nv21ToJpeg(ImageFilter.ResultImage resultImage, int orientation, TotalCaptureResult result) {
+ public byte[] nv21ToJpeg(ImageFilter.ResultImage resultImage, int orientation, TotalCaptureResult result) {
BitmapOutputStream bos = new BitmapOutputStream(1024);
YuvImage im = new YuvImage(resultImage.outBuffer.array(), ImageFormat.NV21,
resultImage.width, resultImage.height, new int[]{resultImage.stride, resultImage.stride});
diff --git a/src/com/android/camera/imageprocessor/filter/DeepPortraitFilter.java b/src/com/android/camera/imageprocessor/filter/DeepPortraitFilter.java
new file mode 100755
index 000000000..9cadcf325
--- /dev/null
+++ b/src/com/android/camera/imageprocessor/filter/DeepPortraitFilter.java
@@ -0,0 +1,325 @@
+/*
+ * 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 com.android.camera.imageprocessor.filter;
+
+import android.graphics.Bitmap;
+import android.graphics.Color;
+import android.graphics.Rect;
+import android.hardware.camera2.CameraAccessException;
+import android.hardware.camera2.CameraCaptureSession;
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CaptureRequest;
+import android.media.Image;
+import android.os.AsyncTask;
+import android.os.Environment;
+import android.os.Handler;
+import android.util.Log;
+import android.util.Size;
+
+import com.android.camera.CaptureModule;
+import com.android.camera.deepportrait.CamGLRenderer;
+import com.android.camera.deepportrait.DPImage;
+
+import java.io.File;
+import java.nio.ByteBuffer;
+import java.util.List;
+
+public class DeepPortraitFilter implements ImageFilter {
+ private static String TAG = "DeepPortraitFilter";
+ private static String VIDEO_DLC = "deepportrait_preview.dlce";
+ private static String SNAPSHOT_DLC = "deepportrait_snapshot.dlce";
+ private static String SD_ROOT_PATH = Environment.getExternalStorageDirectory().toString();
+ private static boolean mIsSupported = false;
+ int mWidth;
+ int mHeight;
+ int mSnapshotWidth;
+ int mSnapshotHeight;
+ int mStrideY;
+ int mStrideVU;
+ private CaptureModule mModule;
+ private CamGLRenderer mRender;
+ private Boolean mDPInitialized = false;
+ private Boolean mDPStillInit = false;
+ private int mVideoMaskSize = 0;
+ private static final int DP_QUEUE_SIZE = 30;
+ private ByteBuffer[] mMaskBufArray = new ByteBuffer[DP_QUEUE_SIZE];
+ private int mSeqNo;
+
+ public DeepPortraitFilter(CaptureModule module, CamGLRenderer render) {
+ mModule = module;
+ mRender = render;
+ }
+
+ @Override
+ public List<CaptureRequest> setRequiredImages(CaptureRequest.Builder builder) {
+ return null;
+ }
+
+ @Override
+ public String getStringName() {
+ return null;
+ }
+
+ @Override
+ public int getNumRequiredImage() {
+ return 0;
+ }
+
+ @Override
+ public void init(int width, int height, int strideY, int strideVU) {
+ mWidth = width;
+ mHeight = height;
+ mStrideY = strideY;
+ mStrideVU = strideVU;
+ mSeqNo = 0;
+ mDPInitialized = initPreview(width, height);
+ if (mDPInitialized) {
+ mVideoMaskSize = getMaskBufferSize();
+ for ( int i = 0; i < mMaskBufArray.length; ++i ) {
+ mMaskBufArray[i] = ByteBuffer.allocateDirect(mVideoMaskSize);
+ }
+ }
+ Log.d(TAG,"init width = " +width +" height = " + height);
+ }
+
+ public void initSnapshot(int width, int height) {
+ String dlcPath = SD_ROOT_PATH + File.separator + SNAPSHOT_DLC;
+ File dlc = new File(dlcPath);
+ if (!dlc.exists()) {
+ mDPStillInit = false;
+ return;
+ }
+ mSnapshotWidth = width;
+ mSnapshotHeight = height;
+ new InitializeDpSnapShot().execute();
+ Log.d(TAG,"initSnapshot width = " +width +" height = " + height);
+ }
+
+ public boolean initPreview(int width, int height) {
+ String dlcPath = SD_ROOT_PATH + File.separator + VIDEO_DLC;
+ File dlc = new File(dlcPath);
+ if (!dlc.exists()) {
+ return false;
+ }
+ return initVideoDeepPortrait(width, height);
+ }
+
+ public boolean getDPInitialized() {
+ return mDPInitialized;
+ }
+
+ public boolean getDPStillInit() {
+ return mDPStillInit;
+ }
+
+ @Override
+ public void deinit() {
+ mDPInitialized = false;
+ mDPStillInit = false;
+ }
+
+ @Override
+ //inputimage is DPimage, imageNum > 0 preview ; imageNum = 0 snapshot
+ public void addImage(ByteBuffer bY, ByteBuffer bVU, int imageNum, Object inputImage) {
+ DPImage dpImage = (DPImage)inputImage;
+ Image image = dpImage.mImage;
+ Image.Plane[] planes = image.getPlanes();
+ ByteBuffer bufferY = planes[0].getBuffer();
+ ByteBuffer bufferC = planes[2].getBuffer();
+ if (imageNum > 0) {
+ mSeqNo++;
+ ByteBuffer mask = mMaskBufArray[mSeqNo % mMaskBufArray.length];
+ dpImage.mMask = mask;
+ dpImage.mSeqNumber = mSeqNo;
+ int displayOrientation = mModule.getDisplayOrientation() == -1?
+ 0:mModule.getDisplayOrientation();
+ int sensorOrientation = mModule.getSensorOrientation();
+ int adjustedRotation = ( sensorOrientation - displayOrientation + 360 ) % 360;
+ dpImage.mOrientation = adjustedRotation;
+ runDpVideoWarpMask( bufferY, bufferC, planes[0].getRowStride(),
+ planes[2].getRowStride(),adjustedRotation,mask,getMaskWidth());
+ } else {
+ int[] maskSize = new int[2];
+ boolean success = false;
+ if (mDPStillInit) {
+ success = getSnapshotMaskBufferSize(mSnapshotWidth,mSnapshotHeight,maskSize);
+ }
+ int maskWidth = maskSize[0];
+ int maskHeight = maskSize[1];
+ int size = maskWidth * maskHeight;
+ if (!success || size == 0) {
+ Log.d(TAG,"failed to get SnapshotMaskBufferSize success = "
+ + success +" size = " + size);
+ return;
+ }
+ ByteBuffer mask = ByteBuffer.allocateDirect(maskWidth * maskHeight);
+ dpImage.mMask = mask;
+ dpImage.mMaskWidth = maskWidth;
+ dpImage.mMaskHeight = maskHeight;
+ int displayOrientation = mModule.getDisplayOrientation() == -1?
+ 0:mModule.getDisplayOrientation();
+ int sensorOrientation = mModule.getSensorOrientation();
+ int adjustedRotation = ( sensorOrientation - displayOrientation + 360 ) % 360;
+ dpImage.mOrientation = adjustedRotation;
+ runDpSnapshotWarpMask(bufferY,bufferC,
+ planes[0].getRowStride(), planes[2].getRowStride(),
+ mask,maskWidth,adjustedRotation);
+ }
+ }
+
+ @Override
+ public ResultImage processImage() {
+ return null;
+ }
+
+ public boolean renderDeepportraitImage(DPImage dpImage,ByteBuffer dstY, ByteBuffer dstVU,
+ int effect, float intensity) {
+ boolean ret;
+ Image image = dpImage.mImage;
+ Image.Plane[] planes = image.getPlanes();
+ ByteBuffer bufferY = planes[0].getBuffer();
+ ByteBuffer bufferC = planes[2].getBuffer();
+ int width = image.getWidth();
+ int height = image.getHeight();
+ int strideY = planes[0].getRowStride();
+ int strideVU = planes[2].getRowStride();
+ if (dpImage.mMask == null) {
+ return false;
+ }
+ ret = initDpEffect(bufferY,bufferC,width,height,strideY,strideVU,
+ dpImage.mMask,dpImage.mMaskWidth,dpImage.mMaskHeight,dpImage.mMaskWidth);
+ Log.d(TAG,"initDpEffect success = " + ret);
+ if (ret) {
+ ret = renderDpEffect(dstY,dstVU,width,height,strideY,strideVU,effect,intensity,
+ dpImage.mOrientation);
+ Log.d(TAG,"renderDpEffect success = " + ret);
+ }
+ return ret;
+ }
+
+ public static Bitmap DpMaskToImage(ByteBuffer maskBuffer, int width, int height) {
+ byte[] maskArray = new byte[width * height];
+ maskBuffer.get(maskArray);
+ int[] rgbArray = new int[maskArray.length];
+ for (int i = 0; i < maskArray.length; i++) {
+ int alpha = (int) maskArray[i];
+ rgbArray[i] = Color.rgb(alpha,alpha,alpha);
+ }
+ Bitmap maskImage = Bitmap.createBitmap(rgbArray,width,height, Bitmap.Config.ARGB_8888);
+ return maskImage;
+ }
+
+ @Override
+ public boolean isSupported() {
+ return mIsSupported;
+ }
+
+ public static boolean isSupportedStatic(){return mIsSupported;}
+
+ @Override
+ public boolean isFrameListener() {
+ return false;
+ }
+
+ @Override
+ public boolean isManualMode() {
+ return false;
+ }
+
+ @Override
+ public void manualCapture(CaptureRequest.Builder builder, CameraCaptureSession captureSession,
+ CameraCaptureSession.CaptureCallback callback,
+ Handler handler) throws CameraAccessException {
+
+ }
+
+ private class InitializeDpSnapShot extends AsyncTask<Void, Void, Void>
+ {
+
+ @Override
+ protected void onPreExecute()
+ {
+ super.onPreExecute();
+ }
+
+ @Override
+ protected void onPostExecute(Void params)
+ {
+ super.onPostExecute(params);
+ }
+
+ @Override
+ protected Void doInBackground(Void... params)
+ {
+
+ if ( !mDPStillInit ) {
+ mDPStillInit = initSnapshotDeepPortrait(mSnapshotWidth, mSnapshotHeight);
+ }
+ return null;
+ }
+ }
+
+ public int getDpMaskWidth() {
+ return getMaskWidth();
+ }
+
+ public int getDpMaskHieght() {
+ return getMaskHeight();
+ }
+
+
+ private native boolean initVideoDeepPortrait(int width, int height);
+ private native boolean initSnapshotDeepPortrait(int width, int height);
+ private native boolean runDpVideoWarpMask(ByteBuffer yData, ByteBuffer vuData, int yStride,
+ int vuStride, int orientation,
+ ByteBuffer mask, int maskStride);
+ private native boolean runDpSnapshotWarpMask(ByteBuffer yData, ByteBuffer vuData, int yStride,
+ int vuStride, ByteBuffer mask, int maskStride,
+ int orientation);
+ private native boolean getSnapshotMaskBufferSize(int width, int height, int[] maskSize);
+ private native int getMaskBufferSize( );
+ private native int getMaskWidth( );
+ private native int getMaskHeight( );
+ private native boolean initDpEffect(ByteBuffer yData, ByteBuffer vuData, int width, int height,
+ int yStride, int vuStride, ByteBuffer mask, int maskWidth,
+ int maskHeight,int maskStride);
+ private native boolean renderDpEffect(ByteBuffer dstYData, ByteBuffer dstVUData,int width,
+ int height, int yStride, int vuStride,int effect,
+ float intensity, int orientation);
+
+ static {
+ try {
+ System.loadLibrary("jni_deepportrait");
+ mIsSupported = true;
+ }catch(UnsatisfiedLinkError e) {
+ mIsSupported = false;
+ Log.d(TAG,"failed to load jni_deepportrait");
+ }
+ }
+}
diff --git a/src/com/android/camera/ui/OneUICameraControls.java b/src/com/android/camera/ui/OneUICameraControls.java
index 8d156e3fe..504cb2679 100755
--- a/src/com/android/camera/ui/OneUICameraControls.java
+++ b/src/com/android/camera/ui/OneUICameraControls.java
@@ -58,6 +58,7 @@ public class OneUICameraControls extends RotatableLayout {
private View mPreview;
private View mSceneModeSwitcher;
private View mFilterModeSwitcher;
+ private View mDeepportraitSwitcher;
private View mMakeupSeekBar;
private View mMakeupSeekBarLowText;
private View mMakeupSeekBarHighText;
@@ -152,6 +153,7 @@ public class OneUICameraControls extends RotatableLayout {
mMakeupSeekBarLayout = findViewById(R.id.makeup_seekbar_layout);
((SeekBar)mMakeupSeekBar).setMax(100);
mFlashButton = findViewById(R.id.flash_button);
+ mDeepportraitSwitcher = findViewById(R.id.deepportrait_switcher);
mMute = findViewById(R.id.mute_button);
mPreview = findViewById(R.id.preview_thumb);
mSceneModeSwitcher = findViewById(R.id.scene_mode_switcher);
@@ -229,8 +231,8 @@ public class OneUICameraControls extends RotatableLayout {
mViews = new View[]{
mSceneModeSwitcher, mFilterModeSwitcher, mFrontBackSwitcher,
- mTsMakeupSwitcher, mFlashButton, mShutter, mPreview, mVideoShutter,
- mPauseButton, mCancelButton
+ mTsMakeupSwitcher,mDeepportraitSwitcher, mFlashButton, mShutter,
+ mPreview, mVideoShutter, mPauseButton, mCancelButton
};
mBottomLargeSize = getResources().getDimensionPixelSize(
R.dimen.one_ui_bottom_large);
@@ -309,7 +311,12 @@ public class OneUICameraControls extends RotatableLayout {
} else {
v.setY(mHeight - mBottom + (mBottom - h) / 2);
}
- float bW = mWidth / 5f;
+ float bW;
+ if (top) {
+ bW = mWidth / 6f;
+ } else {
+ bW = mWidth / 5f;
+ }
v.setX(bW * idx + (bW - w) / 2);
}
@@ -341,6 +348,7 @@ public class OneUICameraControls extends RotatableLayout {
setLocation(mFrontBackSwitcher, true, 2);
setLocation(mTsMakeupSwitcher, true, 3);
setLocation(mFlashButton, true, 4);
+ setLocation(mDeepportraitSwitcher,true,5);
if (mIntentMode == CaptureModule.INTENT_MODE_CAPTURE) {
setLocation(mShutter, false, 2);
setLocation(mCancelButton, false, 0.85f);