diff --git a/.idea/AndroidProjectSystem.xml b/.idea/AndroidProjectSystem.xml
new file mode 100644
index 0000000..4a53bee
--- /dev/null
+++ b/.idea/AndroidProjectSystem.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/appInsightsSettings.xml b/.idea/appInsightsSettings.xml
new file mode 100644
index 0000000..f185e98
--- /dev/null
+++ b/.idea/appInsightsSettings.xml
@@ -0,0 +1,40 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/compiler.xml b/.idea/compiler.xml
index 61a9130..b86273d 100644
--- a/.idea/compiler.xml
+++ b/.idea/compiler.xml
@@ -1,6 +1,6 @@
-
+
\ No newline at end of file
diff --git a/.idea/deploymentTargetSelector.xml b/.idea/deploymentTargetSelector.xml
new file mode 100644
index 0000000..b268ef3
--- /dev/null
+++ b/.idea/deploymentTargetSelector.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml
index a5f05cd..c9dbc09 100644
--- a/.idea/jarRepositories.xml
+++ b/.idea/jarRepositories.xml
@@ -21,5 +21,15 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/migrations.xml b/.idea/migrations.xml
new file mode 100644
index 0000000..f8051a6
--- /dev/null
+++ b/.idea/migrations.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
index d5d35ec..74dd639 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -1,6 +1,7 @@
-
+
+
diff --git a/.idea/runConfigurations.xml b/.idea/runConfigurations.xml
index 7f68460..16660f1 100644
--- a/.idea/runConfigurations.xml
+++ b/.idea/runConfigurations.xml
@@ -3,9 +3,14 @@
-
-
-
+
+
+
+
+
+
+
+
diff --git a/README.md b/README.md
index 9d232e4..da42101 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,22 @@
# quickstart-android-java
-To run the example
-* Go to https://developer.deepar.ai, sign up, create the project and the Android app, copy the license key and paste it to MainActivity.java (instead of your_license_key_goes_here string)
-* Download the SDK from https://developer.deepar.ai and copy the deepar.aar into quickstart-android-java/deepar folder
\ No newline at end of file
+## Overview
+
+This is an example app demonstrating DeepAR SDK.
+
+- Preview of fun face filters, effects and background replacement.
+- Carousel with filter thumbnails.
+- Take screenshot.
+- Record video.
+- Front and back camera.
+- Source code demonstrates how to integrate DeepAR for Android in your app.
+
+For more info on DeepAR for Android see: https://docs.deepar.ai/deepar-sdk/platforms/android/overview
+
+## How to run
+
+1. Open the project in Android Studio.
+2. Create a DeepAR developer account: https://developer.deepar.ai/signup.
+3. Create a project: https://developer.deepar.ai/projects.
+4. Add a Android app to the project. Note that you need to specify the `applicationId` of your app. The `applicationId` is located in the `app/build.gradle` and in this case it is "ai.deepar.deepar_example".
+5. Copy the generated license key in the `MainActivity.java` instead of your_license_key_here.
diff --git a/app/build.gradle b/app/build.gradle
index c8140db..a346ee1 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -1,34 +1,42 @@
apply plugin: 'com.android.application'
android {
- compileSdkVersion 28
defaultConfig {
applicationId "ai.deepar.deepar_example"
- minSdkVersion 19
- targetSdkVersion 28
+ minSdkVersion 23
+ targetSdkVersion 36
+ compileSdk 36
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
+ signingConfig signingConfigs.debug
}
buildTypes {
release {
- minifyEnabled false
+ minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
-}
-repositories {
- flatDir {
- dirs '../deepar'
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_11
+ targetCompatibility JavaVersion.VERSION_11
}
+ namespace 'ai.deepar.deepar_example'
}
dependencies {
- implementation fileTree(dir: 'libs', include: ['*.jar'])
- implementation 'androidx.appcompat:appcompat:1.0.2'
- implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
- testImplementation 'junit:junit:4.12'
- implementation (name: 'deepar', ext:'aar')
- androidTestImplementation 'androidx.test.ext:junit:1.1.0'
- androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1'
+ implementation 'androidx.appcompat:appcompat:1.7.1'
+ implementation 'androidx.constraintlayout:constraintlayout:2.2.1'
+ implementation 'com.google.android.material:material:1.13.0'
+ implementation 'androidx.navigation:navigation-fragment:2.9.5'
+ implementation 'androidx.navigation:navigation-ui:2.9.5'
+ testImplementation 'junit:junit:4.13.2'
+ implementation "ai.deepar.ar:DeepAR:5.6.20"
+ androidTestImplementation 'androidx.test.ext:junit:1.3.0'
+ androidTestImplementation 'androidx.test.espresso:espresso-core:3.7.0'
+ def camerax_version = "1.5.0"
+ implementation "androidx.camera:camera-core:$camerax_version"
+ implementation "androidx.camera:camera-camera2:$camerax_version"
+ implementation "androidx.camera:camera-lifecycle:$camerax_version"
+ implementation "androidx.camera:camera-view:$camerax_version"
}
diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro
index f1b4245..4986800 100644
--- a/app/proguard-rules.pro
+++ b/app/proguard-rules.pro
@@ -19,3 +19,12 @@
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
+
+-keepclassmembers class ai.deepar.ar.DeepAR { *; }
+-keepclassmembers class ai.deepar.ar.ARTouchInfo { *; }
+-keepclassmembers class ai.deepar.ar.ARTouchType { *; }
+-keepclassmembers class ai.deepar.ar.core.videotexture.VideoTextureAndroidJava { *; }
+
+-keep class ai.deepar.ar.ARTouchInfo
+-keep class ai.deepar.ar.ARTouchType
+-keep class ai.deepar.ar.core.videotexture.VideoTextureAndroidJava
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index c272dbf..bbf88ef 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -1,6 +1,12 @@
-
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+ android:theme="@style/AppTheme.NoActionBar" />
+
@@ -21,9 +37,5 @@
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/assets/Elephant_Trunk.deepar b/app/src/main/assets/Elephant_Trunk.deepar
new file mode 100755
index 0000000..d8fa37c
Binary files /dev/null and b/app/src/main/assets/Elephant_Trunk.deepar differ
diff --git a/app/src/main/assets/Emotion_Meter.deepar b/app/src/main/assets/Emotion_Meter.deepar
new file mode 100755
index 0000000..839be00
Binary files /dev/null and b/app/src/main/assets/Emotion_Meter.deepar differ
diff --git a/app/src/main/assets/Emotions_Exaggerator.deepar b/app/src/main/assets/Emotions_Exaggerator.deepar
new file mode 100755
index 0000000..2b5e550
Binary files /dev/null and b/app/src/main/assets/Emotions_Exaggerator.deepar differ
diff --git a/app/src/main/assets/Fire_Effect.deepar b/app/src/main/assets/Fire_Effect.deepar
new file mode 100755
index 0000000..4d903c4
Binary files /dev/null and b/app/src/main/assets/Fire_Effect.deepar differ
diff --git a/app/src/main/assets/Hope.deepar b/app/src/main/assets/Hope.deepar
new file mode 100755
index 0000000..bc55ab3
Binary files /dev/null and b/app/src/main/assets/Hope.deepar differ
diff --git a/app/src/main/assets/Humanoid.deepar b/app/src/main/assets/Humanoid.deepar
new file mode 100755
index 0000000..a04a39b
Binary files /dev/null and b/app/src/main/assets/Humanoid.deepar differ
diff --git a/app/src/main/assets/MakeupLook.deepar b/app/src/main/assets/MakeupLook.deepar
new file mode 100755
index 0000000..7c47b8e
Binary files /dev/null and b/app/src/main/assets/MakeupLook.deepar differ
diff --git a/app/src/main/assets/Neon_Devil_Horns.deepar b/app/src/main/assets/Neon_Devil_Horns.deepar
new file mode 100755
index 0000000..ec79a7d
Binary files /dev/null and b/app/src/main/assets/Neon_Devil_Horns.deepar differ
diff --git a/app/src/main/assets/Ping_Pong.deepar b/app/src/main/assets/Ping_Pong.deepar
new file mode 100644
index 0000000..5a43d93
Binary files /dev/null and b/app/src/main/assets/Ping_Pong.deepar differ
diff --git a/app/src/main/assets/Pixel_Hearts.deepar b/app/src/main/assets/Pixel_Hearts.deepar
new file mode 100644
index 0000000..f1180f5
Binary files /dev/null and b/app/src/main/assets/Pixel_Hearts.deepar differ
diff --git a/app/src/main/assets/Snail.deepar b/app/src/main/assets/Snail.deepar
new file mode 100755
index 0000000..b54e14c
Binary files /dev/null and b/app/src/main/assets/Snail.deepar differ
diff --git a/app/src/main/assets/Split_View_Look.deepar b/app/src/main/assets/Split_View_Look.deepar
new file mode 100755
index 0000000..8d2b002
Binary files /dev/null and b/app/src/main/assets/Split_View_Look.deepar differ
diff --git a/app/src/main/assets/Stallone.deepar b/app/src/main/assets/Stallone.deepar
new file mode 100755
index 0000000..4660e89
Binary files /dev/null and b/app/src/main/assets/Stallone.deepar differ
diff --git a/app/src/main/assets/Vendetta_Mask.deepar b/app/src/main/assets/Vendetta_Mask.deepar
new file mode 100755
index 0000000..3458c55
Binary files /dev/null and b/app/src/main/assets/Vendetta_Mask.deepar differ
diff --git a/app/src/main/assets/aviators b/app/src/main/assets/aviators
deleted file mode 100644
index 5caee65..0000000
Binary files a/app/src/main/assets/aviators and /dev/null differ
diff --git a/app/src/main/assets/background_segmentation b/app/src/main/assets/background_segmentation
deleted file mode 100644
index eb70b8a..0000000
Binary files a/app/src/main/assets/background_segmentation and /dev/null differ
diff --git a/app/src/main/assets/beard b/app/src/main/assets/beard
deleted file mode 100644
index 4244890..0000000
Binary files a/app/src/main/assets/beard and /dev/null differ
diff --git a/app/src/main/assets/bigmouth b/app/src/main/assets/bigmouth
deleted file mode 100644
index c76f884..0000000
Binary files a/app/src/main/assets/bigmouth and /dev/null differ
diff --git a/app/src/main/assets/bleachbypass b/app/src/main/assets/bleachbypass
deleted file mode 100644
index 4501527..0000000
Binary files a/app/src/main/assets/bleachbypass and /dev/null differ
diff --git a/app/src/main/assets/blizzard b/app/src/main/assets/blizzard
deleted file mode 100644
index d88467d..0000000
Binary files a/app/src/main/assets/blizzard and /dev/null differ
diff --git a/app/src/main/assets/burning_effect.deepar b/app/src/main/assets/burning_effect.deepar
new file mode 100755
index 0000000..473a136
Binary files /dev/null and b/app/src/main/assets/burning_effect.deepar differ
diff --git a/app/src/main/assets/dalmatian b/app/src/main/assets/dalmatian
deleted file mode 100644
index 888bf04..0000000
Binary files a/app/src/main/assets/dalmatian and /dev/null differ
diff --git a/app/src/main/assets/drawingmanga b/app/src/main/assets/drawingmanga
deleted file mode 100644
index b2c6ff2..0000000
Binary files a/app/src/main/assets/drawingmanga and /dev/null differ
diff --git a/app/src/main/assets/fatify b/app/src/main/assets/fatify
deleted file mode 100644
index 223d672..0000000
Binary files a/app/src/main/assets/fatify and /dev/null differ
diff --git a/app/src/main/assets/filmcolorperfection b/app/src/main/assets/filmcolorperfection
deleted file mode 100644
index 54a2f99..0000000
Binary files a/app/src/main/assets/filmcolorperfection and /dev/null differ
diff --git a/app/src/main/assets/fire b/app/src/main/assets/fire
deleted file mode 100644
index 9d4c751..0000000
Binary files a/app/src/main/assets/fire and /dev/null differ
diff --git a/app/src/main/assets/flower_face.deepar b/app/src/main/assets/flower_face.deepar
new file mode 100755
index 0000000..7aa9474
Binary files /dev/null and b/app/src/main/assets/flower_face.deepar differ
diff --git a/app/src/main/assets/flowers b/app/src/main/assets/flowers
deleted file mode 100644
index 329551c..0000000
Binary files a/app/src/main/assets/flowers and /dev/null differ
diff --git a/app/src/main/assets/fxdrunk b/app/src/main/assets/fxdrunk
deleted file mode 100644
index 71ba0f0..0000000
Binary files a/app/src/main/assets/fxdrunk and /dev/null differ
diff --git a/app/src/main/assets/galaxy_background.deepar b/app/src/main/assets/galaxy_background.deepar
new file mode 100755
index 0000000..8ff7836
Binary files /dev/null and b/app/src/main/assets/galaxy_background.deepar differ
diff --git a/app/src/main/assets/grumpycat b/app/src/main/assets/grumpycat
deleted file mode 100644
index 38b36d3..0000000
Binary files a/app/src/main/assets/grumpycat and /dev/null differ
diff --git a/app/src/main/assets/heart b/app/src/main/assets/heart
deleted file mode 100644
index 32f3c4e..0000000
Binary files a/app/src/main/assets/heart and /dev/null differ
diff --git a/app/src/main/assets/koala b/app/src/main/assets/koala
deleted file mode 100644
index 1ca7190..0000000
Binary files a/app/src/main/assets/koala and /dev/null differ
diff --git a/app/src/main/assets/lion b/app/src/main/assets/lion
deleted file mode 100644
index 5655096..0000000
Binary files a/app/src/main/assets/lion and /dev/null differ
diff --git a/app/src/main/assets/mudmask b/app/src/main/assets/mudmask
deleted file mode 100644
index b139c0e..0000000
Binary files a/app/src/main/assets/mudmask and /dev/null differ
diff --git a/app/src/main/assets/obama b/app/src/main/assets/obama
deleted file mode 100644
index 2744c61..0000000
Binary files a/app/src/main/assets/obama and /dev/null differ
diff --git a/app/src/main/assets/pug b/app/src/main/assets/pug
deleted file mode 100644
index e8dcfcc..0000000
Binary files a/app/src/main/assets/pug and /dev/null differ
diff --git a/app/src/main/assets/rain b/app/src/main/assets/rain
deleted file mode 100644
index 50a9a35..0000000
Binary files a/app/src/main/assets/rain and /dev/null differ
diff --git a/app/src/main/assets/realvhs b/app/src/main/assets/realvhs
deleted file mode 100644
index c4ef75f..0000000
Binary files a/app/src/main/assets/realvhs and /dev/null differ
diff --git a/app/src/main/assets/sepia b/app/src/main/assets/sepia
deleted file mode 100644
index 92f520a..0000000
Binary files a/app/src/main/assets/sepia and /dev/null differ
diff --git a/app/src/main/assets/slash b/app/src/main/assets/slash
deleted file mode 100644
index 2ccd82d..0000000
Binary files a/app/src/main/assets/slash and /dev/null differ
diff --git a/app/src/main/assets/sleepingmask b/app/src/main/assets/sleepingmask
deleted file mode 100644
index 3035607..0000000
Binary files a/app/src/main/assets/sleepingmask and /dev/null differ
diff --git a/app/src/main/assets/smallface b/app/src/main/assets/smallface
deleted file mode 100644
index 28e8064..0000000
Binary files a/app/src/main/assets/smallface and /dev/null differ
diff --git a/app/src/main/assets/teddycigar b/app/src/main/assets/teddycigar
deleted file mode 100644
index 6901a46..0000000
Binary files a/app/src/main/assets/teddycigar and /dev/null differ
diff --git a/app/src/main/assets/tripleface b/app/src/main/assets/tripleface
deleted file mode 100644
index ed41b02..0000000
Binary files a/app/src/main/assets/tripleface and /dev/null differ
diff --git a/app/src/main/assets/tv80 b/app/src/main/assets/tv80
deleted file mode 100644
index 906c628..0000000
Binary files a/app/src/main/assets/tv80 and /dev/null differ
diff --git a/app/src/main/assets/twistedface b/app/src/main/assets/twistedface
deleted file mode 100644
index 80cc7a4..0000000
Binary files a/app/src/main/assets/twistedface and /dev/null differ
diff --git a/app/src/main/assets/viking_helmet.deepar b/app/src/main/assets/viking_helmet.deepar
new file mode 100755
index 0000000..2b9bdf4
Binary files /dev/null and b/app/src/main/assets/viking_helmet.deepar differ
diff --git a/app/src/main/java/ai/deepar/deepar_example/ARSurfaceProvider.java b/app/src/main/java/ai/deepar/deepar_example/ARSurfaceProvider.java
new file mode 100644
index 0000000..88e67c9
--- /dev/null
+++ b/app/src/main/java/ai/deepar/deepar_example/ARSurfaceProvider.java
@@ -0,0 +1,156 @@
+package ai.deepar.deepar_example;
+
+import android.app.Activity;
+import android.content.Context;
+import android.graphics.SurfaceTexture;
+import android.opengl.EGL14;
+import android.util.Log;
+import android.util.Size;
+import android.view.Surface;
+
+import androidx.annotation.NonNull;
+import androidx.camera.core.Preview;
+import androidx.camera.core.SurfaceRequest;
+import androidx.core.content.ContextCompat;
+
+import java.util.Timer;
+import java.util.TimerTask;
+
+import ai.deepar.ar.DeepAR;
+
+/**
+ * Surface provider used for CameraX preview use-case that provides DeepAR's external GL texture
+ * wrapped in SurfaceTexture.
+ */
+public class ARSurfaceProvider implements Preview.SurfaceProvider {
+ private static final String tag = ARSurfaceProvider.class.getSimpleName();
+
+ ARSurfaceProvider(Context context, DeepAR deepAR) {
+ this.context = context;
+ this.deepAR = deepAR;
+ }
+
+ private void printEglState() {
+ Log.d(tag, "display: " + EGL14.eglGetCurrentDisplay().getNativeHandle() + ", context: " + EGL14.eglGetCurrentContext().getNativeHandle());
+ }
+
+ @Override
+ public void onSurfaceRequested(@NonNull SurfaceRequest request) {
+ Log.d(tag, "Surface requested");
+ printEglState();
+
+ // request the external gl texture from deepar
+ if(nativeGLTextureHandle == 0) {
+ nativeGLTextureHandle = deepAR.getExternalGlTexture();
+ Log.d(tag, "request new external GL texture");
+ printEglState();
+ }
+
+ // if external gl texture could not be provided
+ if(nativeGLTextureHandle == 0) {
+ request.willNotProvideSurface();
+ return;
+ }
+
+ // if external GL texture is provided create SurfaceTexture from it
+ // and register onFrameAvailable listener to
+ Size resolution = request.getResolution();
+ if(surfaceTexture == null) {
+ surfaceTexture = new SurfaceTexture(nativeGLTextureHandle);
+ surfaceTexture.setOnFrameAvailableListener(__ -> {
+ if(stop) {
+ return;
+ }
+ surfaceTexture.updateTexImage();
+ if(isNotifyDeepar) {
+ deepAR.receiveFrameExternalTexture(resolution.getWidth(), resolution.getHeight(), orientation, mirror, nativeGLTextureHandle);
+ }
+ });
+ }
+ surfaceTexture.setDefaultBufferSize(resolution.getWidth(), resolution.getHeight());
+
+ if(surface == null) {
+ surface = new Surface(surfaceTexture);
+ }
+
+ // register transformation listener to listen for screen orientation changes
+ request.setTransformationInfoListener(ContextCompat.getMainExecutor(context), transformationInfo -> orientation = transformationInfo.getRotationDegrees());
+
+ request.provideSurface(surface, ContextCompat.getMainExecutor(context), result -> {
+ switch (result.getResultCode()) {
+ case SurfaceRequest.Result.RESULT_SURFACE_USED_SUCCESSFULLY:
+ Log.i(tag, "RESULT_SURFACE_USED_SUCCESSFULLY");
+ break;
+ case SurfaceRequest.Result.RESULT_INVALID_SURFACE:
+ Log.i(tag, "RESULT_INVALID_SURFACE");
+ break;
+ case SurfaceRequest.Result.RESULT_REQUEST_CANCELLED:
+ Log.i(tag, "RESULT_REQUEST_CANCELLED");
+ break;
+ case SurfaceRequest.Result.RESULT_SURFACE_ALREADY_PROVIDED:
+ Log.i(tag, "RESULT_SURFACE_ALREADY_PROVIDED");
+ break;
+ case SurfaceRequest.Result.RESULT_WILL_NOT_PROVIDE_SURFACE:
+ Log.i(tag, "RESULT_WILL_NOT_PROVIDE_SURFACE");
+ break;
+ }
+ });
+ }
+
+ /**
+ * Get the mirror flag. Mirror flag tells the DeepAR weather to mirror the camera frame.
+ * Usually this is set when using front camera.
+ *
+ * @return mirror flag
+ */
+ public boolean isMirror() {
+ return mirror;
+ }
+
+ /**
+ * Set the mirror flag. Mirror flag tells the DeepAR weather to mirror the camera frame.
+ * Usually this is set when using front camera.
+ *
+ * @param mirror mirror flag
+ */
+ public void setMirror(boolean mirror) {
+ this.mirror = mirror;
+ if(surfaceTexture == null || surface == null) {
+ return;
+ }
+
+
+ // when camera changes from front to back, we don't know
+ // when exactly it will happen so we pause feeding the frames
+ // to deepar for 1 second to avoid mirroring image before
+ // the camera actually changed
+ isNotifyDeepar = false;
+ new Timer().schedule(new TimerTask() {
+ @Override
+ public void run() {
+ isNotifyDeepar = true;
+ }
+ }, 1000);
+ }
+
+ /**
+ * Tell the surface provider to stop feeding frames to DeepAR.
+ * Should be called in {@link Activity#onDestroy()} ()}.
+ */
+ public void stop() {
+ stop = true;
+ }
+
+ private boolean isNotifyDeepar = true;
+ private boolean stop = false;
+ private boolean mirror = true;
+ private int orientation = 0;
+
+ private SurfaceTexture surfaceTexture;
+ private Surface surface;
+ private int nativeGLTextureHandle = 0;
+
+ private final DeepAR deepAR;
+ private final Context context;
+}
+
diff --git a/app/src/main/java/ai/deepar/deepar_example/CameraGrabber.java b/app/src/main/java/ai/deepar/deepar_example/CameraGrabber.java
deleted file mode 100644
index ea36fba..0000000
--- a/app/src/main/java/ai/deepar/deepar_example/CameraGrabber.java
+++ /dev/null
@@ -1,362 +0,0 @@
-package ai.deepar.deepar_example;
-
-import android.graphics.ImageFormat;
-import android.graphics.PixelFormat;
-import android.graphics.SurfaceTexture;
-import android.hardware.Camera;
-import android.os.Handler;
-import android.os.HandlerThread;
-import android.util.Log;
-
-import java.io.IOException;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-import java.util.List;
-
-import ai.deepar.ar.CameraResolutionPreset;
-import ai.deepar.ar.DeepAR;
-
-
-/**
- * Created by luka on 19/04/17.
- * This is an example implementation of how the camera frames are fed to the DeepAR SDK. Feel free
- * to use it as is, or modify for your own needs.
- */
-
-
-
-public class CameraGrabber
-{
- private static final String TAG = CameraGrabber.class.getSimpleName();
-
- private static final int NUMBER_OF_BUFFERS=2;
-
- private static int currentCameraDevice = Camera.CameraInfo.CAMERA_FACING_FRONT;
-
- private int width = 640;
- private int height = 480;
- private CameraResolutionPreset resolutionPreset = CameraResolutionPreset.P640x480;
-
- private int screenOrientation = 0;
-
- public CameraGrabber() {
- }
-
- public CameraGrabber(int cameraDevice) {
- CameraGrabber.currentCameraDevice = cameraDevice;
- }
-
- public void setFrameReceiver(DeepAR receiver) {
- if (mThread != null) {
- mThread.setFrameReceiver(receiver, currentCameraDevice);
- }
- }
-
- public void initCamera(CameraGrabberListener listener) {
- if (mThread == null) {
- mThread = new CameraHandlerThread(listener, width, height, screenOrientation);
- }
-
- synchronized (mThread) {
- mThread.openCamera();
- }
- }
-
-
- public void startPreview() {
- if (mThread != null && mThread.camera != null) {
- mThread.camera.startPreview();
- }
- }
-
- public void stopPreview() {
- if (mThread != null && mThread.camera != null ) {
- mThread.camera.stopPreview();
- }
- }
-
- public void changeCameraDevice(int cameraDevice) {
- currentCameraDevice = cameraDevice;
- initCamera(new CameraGrabberListener() {
- @Override
- public void onCameraInitialized() {
- startPreview();
- }
-
- @Override
- public void onCameraError(String errorMsg) {
- Log.e(TAG, errorMsg);
- }
- });
-
- }
-
- public int getCurrCameraDevice() {
- return currentCameraDevice;
- }
-
- public void releaseCamera() {
- if (mThread != null) {
- mThread.releaseCamera();
- mThread = null;
- }
- }
-
- private CameraHandlerThread mThread = null;
-
- public CameraResolutionPreset getResolutionPreset() {
- return resolutionPreset;
- }
-
- public void setResolutionPreset(CameraResolutionPreset resolutionPreset) {
-
- this.resolutionPreset = resolutionPreset;
-
- width = this.resolutionPreset.getWidth();
- height = this.resolutionPreset.getHeight();
-
- if (mThread != null) {
- mThread.reinitCamera(width, height);
- }
-
- }
-
- public int getScreenOrientation() {
- return screenOrientation;
- }
-
- public void setScreenOrientation(int screenOrientation) {
- this.screenOrientation = screenOrientation;
- }
- public Camera getCamera() {
- if (mThread == null) {
- return null;
- }
- return mThread.camera;
- }
-
- private static class CameraHandlerThread extends HandlerThread {
- Handler mHandler = null;
- public Camera camera;
- public SurfaceTexture surface;
- private DeepAR frameReceiver;
- private ByteBuffer[] buffers;
- private int currentBuffer = 0;
- private CameraGrabberListener listener;
- private int cameraOrientation;
- private int width;
- private int height;
- private int screenOrientation;
- CameraHandlerThread(CameraGrabberListener listener, int width, int height, int screenOrientation) {
- super("CameraHandlerThread");
-
- this.listener = listener;
- this.width = width;
- this.height = height;
- this.screenOrientation = screenOrientation;
- start();
- mHandler = new Handler(getLooper());
- }
-
- synchronized void notifyCameraOpened() {
- notify();
- }
-
- synchronized void releaseCamera() {
- if (camera == null) {
- return;
- }
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- camera.stopPreview();
- camera.setPreviewCallbackWithBuffer(null);
- camera.release();
- camera = null;
- mHandler = null;
- listener = null;
- frameReceiver = null;
- surface = null;
- buffers = null;
- quitSafely();
- }
- });
- }
-
- synchronized void setFrameReceiver(DeepAR receiver, final int cameraDevice) {
- frameReceiver = receiver;
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- if (camera == null) {
- return;
- }
- camera.setPreviewCallbackWithBuffer(new Camera.PreviewCallback() {
- public void onPreviewFrame(byte[] data, Camera arg1) {
- if (frameReceiver != null) {
- buffers[currentBuffer].put(data);
- buffers[currentBuffer].position(0);
- if (frameReceiver != null) {
- frameReceiver.receiveFrame(buffers[currentBuffer], width,height, cameraOrientation, cameraDevice == Camera.CameraInfo.CAMERA_FACING_FRONT);
- }
- currentBuffer = ( currentBuffer + 1 ) % NUMBER_OF_BUFFERS;
- }
- if (camera != null) {
- camera.addCallbackBuffer(data);
- }
- }
- });
- }
- });
- }
-
- private void init() {
-
- if (camera != null) {
- camera.setPreviewCallbackWithBuffer(null);
- camera.stopPreview();
- camera.release();
- camera = null;
- }
-
- if (surface == null) {
- surface = new SurfaceTexture(0);
- }
-
- Camera.CameraInfo info = new Camera.CameraInfo();
- int cameraId = -1;
- int numberOfCameras = Camera.getNumberOfCameras();
- for(int i = 0; i < numberOfCameras; i++)
- {
- Camera.getCameraInfo(i, info);
- if(info.facing == currentCameraDevice) {
- cameraOrientation = info.orientation;
-
- if (currentCameraDevice == Camera.CameraInfo.CAMERA_FACING_FRONT) {
- cameraOrientation = (info.orientation + screenOrientation) % 360;
- //cameraOrientation = (360 - cameraOrientation) % 360;
- } else {
- cameraOrientation = (info.orientation - screenOrientation + 360) % 360;
- }
- cameraId = i;
- break;
- }
- }
-
- if(cameraId == -1) {
- if (listener != null) {
- listener.onCameraError("Camera not found error.");
- }
- return;
- }
-
- try {
- camera = Camera.open(cameraId);
- } catch (Exception e) {
- // event error
- if (listener != null) {
- listener.onCameraError("Could not open camera device. Could be used by another process.");
- }
- return;
- }
-
- Camera.Parameters params = camera.getParameters();
-
-
- boolean presetExists = false;
- List availableSizes = camera.getParameters().getSupportedPictureSizes();
- for (Camera.Size size : availableSizes) {
- if (size.width == width && size.height == height) {
- presetExists = true;
- break;
- }
- }
-
- if (!presetExists) {
- Log.e(TAG, "Selected resolution preset is not available on this device");
- listener.onCameraError("Selected preset resolution of " + width + "x" + height + " is not supported for this device.");
- return;
- }
-
- params.setPreviewSize(width, height);
- params.setPictureSize(width, height);
- params.setPictureFormat(PixelFormat.JPEG);
- params.setJpegQuality(90);
- params.setPreviewFormat(ImageFormat.NV21);
-
- /*
- List ranges = params.getSupportedPreviewFpsRange();
- int[] bestRange = {0,0};
-
- for (int[] range : ranges) {
- if (range[0] > bestRange[0]) {
- bestRange[0] = range[0];
- bestRange[1] = range[1];
- }
- }
- params.setPreviewFpsRange(bestRange[0], bestRange[1]);
- */
-
- camera.setParameters(params);
-
-
- buffers = new ByteBuffer[NUMBER_OF_BUFFERS];
- for (int i = 0; i < NUMBER_OF_BUFFERS; i++) {
- buffers[i] = ByteBuffer.allocateDirect(width * height * 3 / 2);
- buffers[i].order(ByteOrder.nativeOrder());
- buffers[i].position(0);
- byte[] buffer = new byte[width * height * 3 / 2];
- camera.addCallbackBuffer(buffer);
- }
-
-
- try {
- camera.setPreviewTexture(surface);
- } catch(IOException ioe) {
- if (listener != null) {
- listener.onCameraError("Error setting preview texture.");
- }
- return;
- }
-
- if (frameReceiver != null) {
- setFrameReceiver(frameReceiver, currentCameraDevice);
- }
- if (listener != null) {
- listener.onCameraInitialized();
- }
- }
-
- void reinitCamera(final int newWidth, final int newHeight) {
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- camera.stopPreview();
- camera.setPreviewCallbackWithBuffer(null);
- camera.release();
- camera = null;
- width = newWidth;
- height = newHeight;
- init();
- }
- });
- }
-
- void openCamera() {
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- init();
- notifyCameraOpened();
- }
- });
- try {
- wait();
- }
- catch (InterruptedException e) {
- Log.w(TAG, "wait was interrupted");
- }
- }
- }
-
-};
\ No newline at end of file
diff --git a/app/src/main/java/ai/deepar/deepar_example/CameraGrabberListener.java b/app/src/main/java/ai/deepar/deepar_example/CameraGrabberListener.java
deleted file mode 100644
index 0a47a4e..0000000
--- a/app/src/main/java/ai/deepar/deepar_example/CameraGrabberListener.java
+++ /dev/null
@@ -1,6 +0,0 @@
-package ai.deepar.deepar_example;
-
-public interface CameraGrabberListener {
- void onCameraInitialized();
- void onCameraError(String errorMsg);
-}
diff --git a/app/src/main/java/ai/deepar/deepar_example/MainActivity.java b/app/src/main/java/ai/deepar/deepar_example/MainActivity.java
index 205db25..fffb0f9 100644
--- a/app/src/main/java/ai/deepar/deepar_example/MainActivity.java
+++ b/app/src/main/java/ai/deepar/deepar_example/MainActivity.java
@@ -1,87 +1,104 @@
package ai.deepar.deepar_example;
-import ai.deepar.ar.ARErrorType;
-import ai.deepar.ar.AREventListener;
-import ai.deepar.ar.CameraResolutionPreset;
-import ai.deepar.ar.DeepAR;
-import androidx.appcompat.app.AppCompatActivity;
-import androidx.core.app.ActivityCompat;
-import androidx.core.content.ContextCompat;
+import static android.os.Environment.getExternalStoragePublicDirectory;
import android.Manifest;
-import android.app.Activity;
-import android.app.AlertDialog;
-import android.content.DialogInterface;
+import android.annotation.SuppressLint;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
-import android.hardware.Camera;
import android.media.Image;
-import android.media.MediaScannerConnection;
+import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.text.format.DateFormat;
import android.util.DisplayMetrics;
+import android.util.Size;
+import android.view.MotionEvent;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.widget.ImageButton;
-import android.widget.RadioButton;
import android.widget.TextView;
import android.widget.Toast;
+import androidx.annotation.NonNull;
+import androidx.appcompat.app.AppCompatActivity;
+import androidx.camera.core.CameraSelector;
+import androidx.camera.core.ImageAnalysis;
+import androidx.camera.core.ImageProxy;
+import androidx.camera.core.Preview;
+import androidx.camera.lifecycle.ProcessCameraProvider;
+import androidx.core.app.ActivityCompat;
+import androidx.core.content.ContextCompat;
+import androidx.lifecycle.LifecycleOwner;
+
+import com.google.common.util.concurrent.ListenableFuture;
+
import java.io.File;
import java.io.FileOutputStream;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
+import java.util.concurrent.ExecutionException;
+
+import ai.deepar.ar.ARErrorType;
+import ai.deepar.ar.AREventListener;
+import ai.deepar.ar.ARTouchInfo;
+import ai.deepar.ar.ARTouchType;
+import ai.deepar.ar.CameraResolutionPreset;
+import ai.deepar.ar.DeepAR;
+import ai.deepar.ar.DeepARImageFormat;
public class MainActivity extends AppCompatActivity implements SurfaceHolder.Callback, AREventListener {
- private CameraGrabber cameraGrabber;
- private int defaultCameraDevice = Camera.CameraInfo.CAMERA_FACING_FRONT;
- private int cameraDevice = defaultCameraDevice;
+ // Default camera lens value, change to CameraSelector.LENS_FACING_BACK to initialize with back camera
+ private final int defaultLensFacing = CameraSelector.LENS_FACING_FRONT;
+ private ARSurfaceProvider surfaceProvider = null;
+ private int lensFacing = defaultLensFacing;
+ private ListenableFuture cameraProviderFuture;
+ private ByteBuffer[] buffers;
+ private int currentBuffer = 0;
+ private static final int NUMBER_OF_BUFFERS=2;
+ private static final boolean useExternalCameraTexture = false;
+
private DeepAR deepAR;
- private int currentMask=0;
private int currentEffect=0;
- private int currentFilter=0;
private int screenOrientation;
- ArrayList masks;
ArrayList effects;
- ArrayList filters;
- private int activeFilterType = 0;
private boolean recording = false;
private boolean currentSwitchRecording = false;
- private String recordingPath = Environment.getExternalStorageDirectory() + File.separator + "video.mp4";
+
+ private int width = 0;
+ private int height = 0;
+
+ private File videoFileName;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
+ }
+ @Override
+ protected void onStart() {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED ||
- ContextCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED ||
- ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
-
- ActivityCompat.requestPermissions(this, new String[]{ Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.RECORD_AUDIO },
+ ContextCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) {
+ ActivityCompat.requestPermissions(this, new String[]{ Manifest.permission.CAMERA, Manifest.permission.RECORD_AUDIO },
1);
} else {
// Permission has already been granted
initialize();
}
-
- }
-
- @Override
- protected void onStart() {
- initialize();
super.onStart();
- setupCamera();
}
@Override
@@ -91,8 +108,8 @@ public void onRequestPermissionsResult(int requestCode, String[] permissions, i
if (grantResult != PackageManager.PERMISSION_GRANTED) {
return; // no permission
}
- initialize();
}
+ initialize();
}
}
@@ -103,58 +120,49 @@ private void initialize() {
}
private void initializeFilters() {
- masks = new ArrayList<>();
- masks.add("none");
- masks.add("aviators");
- masks.add("bigmouth");
- masks.add("dalmatian");
- masks.add("flowers");
- masks.add("koala");
- masks.add("lion");
- masks.add("smallface");
- masks.add("teddycigar");
- masks.add("background_segmentation");
- masks.add("tripleface");
- masks.add("sleepingmask");
- masks.add("fatify");
- masks.add("obama");
- masks.add("mudmask");
- masks.add("pug");
- masks.add("slash");
- masks.add("twistedface");
- masks.add("grumpycat");
-
effects = new ArrayList<>();
effects.add("none");
- effects.add("fire");
- effects.add("rain");
- effects.add("heart");
- effects.add("blizzard");
-
- filters = new ArrayList<>();
- filters.add("none");
- filters.add("filmcolorperfection");
- filters.add("tv80");
- filters.add("drawingmanga");
- filters.add("sepia");
- filters.add("bleachbypass");
+ effects.add("viking_helmet.deepar");
+ effects.add("MakeupLook.deepar");
+ effects.add("Split_View_Look.deepar");
+ effects.add("Emotions_Exaggerator.deepar");
+ effects.add("Emotion_Meter.deepar");
+ effects.add("Stallone.deepar");
+ effects.add("flower_face.deepar");
+ effects.add("galaxy_background.deepar");
+ effects.add("Humanoid.deepar");
+ effects.add("Neon_Devil_Horns.deepar");
+ effects.add("Ping_Pong.deepar");
+ effects.add("Pixel_Hearts.deepar");
+ effects.add("Snail.deepar");
+ effects.add("Hope.deepar");
+ effects.add("Vendetta_Mask.deepar");
+ effects.add("Fire_Effect.deepar");
+ effects.add("burning_effect.deepar");
+ effects.add("Elephant_Trunk.deepar");
+
}
+ @SuppressLint("ClickableViewAccessibility")
private void initalizeViews() {
ImageButton previousMask = findViewById(R.id.previousMask);
ImageButton nextMask = findViewById(R.id.nextMask);
- final RadioButton radioMasks = findViewById(R.id.masks);
- final RadioButton radioEffects = findViewById(R.id.effects);
- final RadioButton radioFilters = findViewById(R.id.filters);
-
SurfaceView arView = findViewById(R.id.surface);
- arView.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- deepAR.onClick();
+ arView.setOnTouchListener((view, motionEvent) -> {
+ switch (motionEvent.getAction()) {
+ case MotionEvent.ACTION_DOWN:
+ deepAR.touchOccurred(new ARTouchInfo(motionEvent.getX(), motionEvent.getY(), ARTouchType.Start));
+ return true;
+ case MotionEvent.ACTION_MOVE:
+ deepAR.touchOccurred(new ARTouchInfo(motionEvent.getX(), motionEvent.getY(), ARTouchType.Move));
+ return true;
+ case MotionEvent.ACTION_UP:
+ deepAR.touchOccurred(new ARTouchInfo(motionEvent.getX(), motionEvent.getY(), ARTouchType.End));
+ return true;
}
+ return false;
});
arView.getHolder().addCallback(this);
@@ -175,8 +183,18 @@ public void onClick(View v) {
switchCamera.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
- cameraDevice = cameraGrabber.getCurrCameraDevice() == Camera.CameraInfo.CAMERA_FACING_FRONT ? Camera.CameraInfo.CAMERA_FACING_BACK : Camera.CameraInfo.CAMERA_FACING_FRONT;
- cameraGrabber.changeCameraDevice(cameraDevice);
+ lensFacing = lensFacing == CameraSelector.LENS_FACING_FRONT ? CameraSelector.LENS_FACING_BACK : CameraSelector.LENS_FACING_FRONT ;
+ //unbind immediately to avoid mirrored frame.
+ ProcessCameraProvider cameraProvider = null;
+ try {
+ cameraProvider = cameraProviderFuture.get();
+ cameraProvider.unbindAll();
+ } catch (ExecutionException e) {
+ e.printStackTrace();
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ setupCamera();
}
});
@@ -186,14 +204,12 @@ public void onClick(View v) {
public void onClick(View v) {
Intent myIntent = new Intent(MainActivity.this, BasicActivity.class);
MainActivity.this.startActivity(myIntent);
- //deepAR.release(); moved to onStop();
}
});
-
final TextView screenShotModeButton = findViewById(R.id.screenshotModeButton);
final TextView recordModeBtn = findViewById(R.id.recordModeButton);
@@ -238,10 +254,15 @@ public void onClick(View v) {
public void onClick(View v) {
if(recording) {
deepAR.stopVideoRecording();
- Toast.makeText(getApplicationContext(), "Saved video to: " + recordingPath, Toast.LENGTH_LONG).show();
+ Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
+ Uri contentUri = Uri.fromFile(videoFileName);
+ mediaScanIntent.setData(contentUri);
+ sendBroadcast(mediaScanIntent);
+ Toast.makeText(getApplicationContext(), "Recording " + videoFileName.getName() + " saved.", Toast.LENGTH_LONG).show();
} else {
- deepAR.startVideoRecording(recordingPath);
- Toast.makeText(getApplicationContext(), "Started video recording!", Toast.LENGTH_SHORT).show();
+ videoFileName = new File(getExternalStoragePublicDirectory(Environment.DIRECTORY_MOVIES), "video_" + new SimpleDateFormat("yyyy_MM_dd_HH_mm_ss").format(new Date()) + ".mp4");
+ deepAR.startVideoRecording(videoFileName.toString(), width/2, height/2);
+ Toast.makeText(getApplicationContext(), "Recording started.", Toast.LENGTH_SHORT).show();
}
recording = !recording;
}
@@ -266,30 +287,6 @@ public void onClick(View view) {
}
});
- radioMasks.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- radioEffects.setChecked(false);
- radioFilters.setChecked(false);
- activeFilterType = 0;
- }
- });
- radioEffects.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- radioMasks.setChecked(false);
- radioFilters.setChecked(false);
- activeFilterType = 1;
- }
- });
- radioFilters.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- radioEffects.setChecked(false);
- radioMasks.setChecked(false);
- activeFilterType = 2;
- }
- });
}
/*
get interface orientation from
@@ -299,8 +296,8 @@ private int getScreenOrientation() {
int rotation = getWindowManager().getDefaultDisplay().getRotation();
DisplayMetrics dm = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(dm);
- int width = dm.widthPixels;
- int height = dm.heightPixels;
+ width = dm.widthPixels;
+ height = dm.heightPixels;
int orientation;
// if the device's natural orientation is portrait:
if ((rotation == Surface.ROTATION_0
@@ -361,50 +358,89 @@ private void initializeDeepAR() {
}
private void setupCamera() {
- cameraGrabber = new CameraGrabber(cameraDevice);
- screenOrientation = getScreenOrientation();
-
- switch (screenOrientation) {
- case ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE:
- cameraGrabber.setScreenOrientation(90);
- break;
- case ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE:
- cameraGrabber.setScreenOrientation(270);
- break;
- default:
- cameraGrabber.setScreenOrientation(0);
- break;
+ cameraProviderFuture = ProcessCameraProvider.getInstance(this);
+ cameraProviderFuture.addListener(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ ProcessCameraProvider cameraProvider = cameraProviderFuture.get();
+ bindImageAnalysis(cameraProvider);
+ } catch (ExecutionException | InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+ }, ContextCompat.getMainExecutor(this));
+ }
+
+ private void bindImageAnalysis(@NonNull ProcessCameraProvider cameraProvider) {
+ CameraResolutionPreset cameraResolutionPreset = CameraResolutionPreset.P1920x1080;
+ int width;
+ int height;
+ int orientation = getScreenOrientation();
+ if (orientation == ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE || orientation ==ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE){
+ width = cameraResolutionPreset.getWidth();
+ height = cameraResolutionPreset.getHeight();
+ } else {
+ width = cameraResolutionPreset.getHeight();
+ height = cameraResolutionPreset.getWidth();
}
- // Available 1080p, 720p and 480p resolutions
- cameraGrabber.setResolutionPreset(CameraResolutionPreset.P1280x720);
+ Size cameraResolution = new Size(width, height);
+ CameraSelector cameraSelector = new CameraSelector.Builder().requireLensFacing(lensFacing).build();
- final Activity context = this;
- cameraGrabber.initCamera(new CameraGrabberListener() {
- @Override
- public void onCameraInitialized() {
- cameraGrabber.setFrameReceiver(deepAR);
- cameraGrabber.startPreview();
- }
+ if(useExternalCameraTexture) {
+ Preview preview = new Preview.Builder()
+ .setTargetResolution(cameraResolution)
+ .build();
- @Override
- public void onCameraError(String errorMsg) {
- AlertDialog.Builder builder = new AlertDialog.Builder(context);
- builder.setTitle("Camera error");
- builder.setMessage(errorMsg);
- builder.setCancelable(true);
- builder.setPositiveButton("Ok", new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialogInterface, int i) {
- dialogInterface.cancel();
- }
- });
- AlertDialog dialog = builder.create();
- dialog.show();
+ cameraProvider.unbindAll();
+ cameraProvider.bindToLifecycle((LifecycleOwner)this, cameraSelector, preview);
+ if(surfaceProvider == null) {
+ surfaceProvider = new ARSurfaceProvider(this, deepAR);
}
- });
+ preview.setSurfaceProvider(surfaceProvider);
+ surfaceProvider.setMirror(lensFacing == CameraSelector.LENS_FACING_FRONT);
+ } else {
+ buffers = new ByteBuffer[NUMBER_OF_BUFFERS];
+ for (int i = 0; i < NUMBER_OF_BUFFERS; i++) {
+ buffers[i] = ByteBuffer.allocateDirect(width * height * 4);
+ buffers[i].order(ByteOrder.nativeOrder());
+ buffers[i].position(0);
+ }
+
+ ImageAnalysis imageAnalysis = new ImageAnalysis.Builder()
+ .setOutputImageFormat(ImageAnalysis.OUTPUT_IMAGE_FORMAT_RGBA_8888)
+ .setTargetResolution(cameraResolution)
+ .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
+ .build();
+ imageAnalysis.setAnalyzer(ContextCompat.getMainExecutor(this), imageAnalyzer);
+ cameraProvider.unbindAll();
+ cameraProvider.bindToLifecycle((LifecycleOwner)this, cameraSelector, imageAnalysis);
+ }
}
+ private ImageAnalysis.Analyzer imageAnalyzer = new ImageAnalysis.Analyzer() {
+ @Override
+ public void analyze(@NonNull ImageProxy image) {
+ ByteBuffer buffer = image.getPlanes()[0].getBuffer();
+ buffer.rewind();
+ buffers[currentBuffer].put(buffer);
+ buffers[currentBuffer].position(0);
+ if (deepAR != null) {
+ deepAR.receiveFrame(buffers[currentBuffer],
+ image.getWidth(), image.getHeight(),
+ image.getImageInfo().getRotationDegrees(),
+ lensFacing == CameraSelector.LENS_FACING_FRONT,
+ DeepARImageFormat.RGBA_8888,
+ image.getPlanes()[0].getPixelStride()
+ );
+ }
+ currentBuffer = (currentBuffer + 1) % NUMBER_OF_BUFFERS;
+ image.close();
+ }
+ };
+
+
private String getFilterPath(String filterName) {
if (filterName.equals("none")) {
return null;
@@ -413,54 +449,43 @@ private String getFilterPath(String filterName) {
}
private void gotoNext() {
- if (activeFilterType == 0) {
- currentMask = (currentMask + 1) % masks.size();
- deepAR.switchEffect("mask", getFilterPath(masks.get(currentMask)));
- } else if (activeFilterType == 1) {
- currentEffect = (currentEffect + 1) % effects.size();
- deepAR.switchEffect("effect", getFilterPath(effects.get(currentEffect)));
- } else if (activeFilterType == 2) {
- currentFilter = (currentFilter + 1) % filters.size();
- deepAR.switchEffect("filter", getFilterPath(filters.get(currentFilter)));
- }
+ currentEffect = (currentEffect + 1) % effects.size();
+ deepAR.switchEffect("effect", getFilterPath(effects.get(currentEffect)));
}
private void gotoPrevious() {
- if (activeFilterType == 0) {
-
- currentMask = (currentMask - 1) % masks.size();
- if (currentMask < 0 ) {
- currentMask = masks.size()-1;
- }
- deepAR.switchEffect("mask", getFilterPath(masks.get(currentMask)));
- } else if (activeFilterType == 1) {
- currentEffect = (currentEffect - 1) % effects.size();
- deepAR.switchEffect("effect", getFilterPath(effects.get(currentEffect)));
- } else if (activeFilterType == 2) {
- currentFilter = (currentFilter - 1) % filters.size();
- deepAR.switchEffect("filter", getFilterPath(filters.get(currentFilter)));
- }
+ currentEffect = (currentEffect - 1 + effects.size()) % effects.size();
+ deepAR.switchEffect("effect", getFilterPath(effects.get(currentEffect)));
}
@Override
protected void onStop() {
- super.onStop();
recording = false;
currentSwitchRecording = false;
- if (cameraGrabber == null) {
- return;
+ ProcessCameraProvider cameraProvider = null;
+ try {
+ cameraProvider = cameraProviderFuture.get();
+ cameraProvider.unbindAll();
+ } catch (ExecutionException e) {
+ e.printStackTrace();
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ if(surfaceProvider != null) {
+ surfaceProvider.stop();
+ surfaceProvider = null;
}
- cameraGrabber.setFrameReceiver(null);
- cameraGrabber.stopPreview();
- cameraGrabber.releaseCamera();
- cameraGrabber = null;
deepAR.release();
deepAR = null;
+ super.onStop();
}
@Override
protected void onDestroy() {
super.onDestroy();
+ if(surfaceProvider != null) {
+ surfaceProvider.stop();
+ }
if (deepAR == null) {
return;
}
@@ -491,14 +516,17 @@ public void surfaceDestroyed(SurfaceHolder holder) {
public void screenshotTaken(Bitmap bitmap) {
CharSequence now = DateFormat.format("yyyy_MM_dd_hh_mm_ss", new Date());
try {
- File imageFile = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES) + "/DeepAR_" + now + ".jpg");
+ File imageFile = new File(getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), "image_" + now + ".jpg");
FileOutputStream outputStream = new FileOutputStream(imageFile);
int quality = 100;
bitmap.compress(Bitmap.CompressFormat.JPEG, quality, outputStream);
outputStream.flush();
outputStream.close();
- MediaScannerConnection.scanFile(MainActivity.this, new String[]{imageFile.toString()}, null, null);
- Toast.makeText(MainActivity.this, "Screenshot saved", Toast.LENGTH_SHORT).show();
+ Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
+ Uri contentUri = Uri.fromFile(imageFile);
+ mediaScanIntent.setData(contentUri);
+ this.sendBroadcast(mediaScanIntent);
+ Toast.makeText(MainActivity.this, "Screenshot " + imageFile.getName() + " saved.", Toast.LENGTH_SHORT).show();
} catch (Throwable e) {
e.printStackTrace();
}
@@ -533,9 +561,7 @@ public void shutdownFinished() {
@Override
public void initialized() {
// Restore effect state after deepar release
- deepAR.switchEffect("mask", getFilterPath(masks.get(currentMask)));
deepAR.switchEffect("effect", getFilterPath(effects.get(currentEffect)));
- deepAR.switchEffect("filter", getFilterPath(filters.get(currentFilter)));
}
@Override
diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml
index b990362..29eb705 100644
--- a/app/src/main/res/layout/activity_main.xml
+++ b/app/src/main/res/layout/activity_main.xml
@@ -25,7 +25,7 @@
android:layout_height="70dp"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
- android:layout_marginBottom="60dp"
+ android:layout_marginBottom="40dp"
android:background="@null"
android:scaleType="centerInside"
android:src="@drawable/record_selector" />
@@ -84,84 +84,6 @@
android:scaleType="centerInside"
android:src="@drawable/arrow_right" />
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-