From f906d5ce349025423f14921199ef2bd43fd9ccab Mon Sep 17 00:00:00 2001 From: n8fr8 Date: Wed, 6 Feb 2019 00:18:27 -0500 Subject: [PATCH 1/4] switch to new CameraView: https://github.com/natario1/CameraView --- build.gradle | 17 +++-- .../main/sensors/motion/CameraViewHolder.java | 65 +++++++++++-------- .../main/sensors/motion/MotionDetector.java | 5 +- .../org/havenapp/main/ui/CameraFragment.java | 9 +-- src/main/res/layout/camera_fragment.xml | 25 ++++++- 5 files changed, 73 insertions(+), 48 deletions(-) diff --git a/build.gradle b/build.gradle index f53a0ed5..0c470549 100644 --- a/build.gradle +++ b/build.gradle @@ -149,7 +149,7 @@ dependencies { implementation 'me.angrybyte.picker:picker:1.3.1' implementation 'com.github.stfalcon:frescoimageviewer:0.5.0' implementation 'com.facebook.fresco:fresco:1.10.0' - // implementation 'com.github.derlio.waveform:library:1.0.3@aar' + implementation 'com.github.derlio:audio-waveform:v1.0.1' implementation 'org.firezenk:audiowaves:1.1@aar' implementation 'com.maxproj.simplewaveform:app:1.0.0' @@ -157,7 +157,7 @@ dependencies { implementation('com.mikepenz:aboutlibraries:6.1.1@aar') { transitive = true } - implementation 'com.asksira.android:cameraviewplus:0.9.5' + implementation 'com.github.halilozercan:BetterVideoPlayer:1.1.0' implementation 'io.github.silvaren:easyrs:0.5.3' implementation 'org.jcodec:jcodec:0.2.3' @@ -171,13 +171,16 @@ dependencies { implementation "android.arch.lifecycle:extensions:1.1.1" testImplementation "junit:junit:4.12" - androidTestImplementation 'androidx.test:runner:1.1.0' - androidTestImplementation 'androidx.test:core:1.0.0' - androidTestImplementation 'androidx.test:rules:1.1.0' - androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.0' - androidTestImplementation 'androidx.test.espresso:espresso-intents:3.1.0' + androidTestImplementation 'androidx.test:runner:1.1.1' + androidTestImplementation 'androidx.test:core:1.1.0' + androidTestImplementation 'androidx.test:rules:1.1.1' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1' + androidTestImplementation 'androidx.test.espresso:espresso-intents:3.1.1' androidTestImplementation "android.arch.persistence.room:testing:1.1.1" // android-job implementation 'com.evernote:android-job:1.2.6' + + // new camera view: https://github.com/natario1/CameraView + implementation 'com.otaliastudios:cameraview:2.0.0-beta02' } diff --git a/src/main/java/org/havenapp/main/sensors/motion/CameraViewHolder.java b/src/main/java/org/havenapp/main/sensors/motion/CameraViewHolder.java index 3baf74bb..51fe280a 100644 --- a/src/main/java/org/havenapp/main/sensors/motion/CameraViewHolder.java +++ b/src/main/java/org/havenapp/main/sensors/motion/CameraViewHolder.java @@ -25,7 +25,11 @@ import android.util.Log; import android.view.Surface; -import com.google.android.cameraview.CameraView; +import com.otaliastudios.cameraview.CameraView; +import com.otaliastudios.cameraview.Facing; +import com.otaliastudios.cameraview.Frame; +import com.otaliastudios.cameraview.FrameProcessor; +import com.otaliastudios.cameraview.Size; import org.havenapp.main.PreferenceManager; import org.havenapp.main.Utils; @@ -46,6 +50,7 @@ import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; +import androidx.annotation.NonNull; import androidx.renderscript.RenderScript; import io.github.silvaren.easyrs.tools.Nv21Image; @@ -202,28 +207,37 @@ public void addListener(MotionDetector.MotionListener listener) { * (preferred is 640x480) * in order to minimize CPU usage */ - public synchronized void startCamera() { + public void startCamera() { updateCamera(); - cameraView.start(); + cameraView.open(); - cameraView.setOnFrameListener((data, width, height, rotationDegrees) -> { + cameraView.addFrameProcessor(new FrameProcessor() { + @Override + public void process(@NonNull Frame frame) { - long now = System.currentTimeMillis(); - if (now < CameraViewHolder.this.lastTimestamp + PREVIEW_INTERVAL) - return; + long now = System.currentTimeMillis(); + if (now < CameraViewHolder.this.lastTimestamp + PREVIEW_INTERVAL) + return; - CameraViewHolder.this.lastTimestamp = now; + CameraViewHolder.this.lastTimestamp = now; - if (!doingVideoProcessing) { + if (frame.getData() != null && frame.getSize() != null) { - Log.i("CameraViewHolder", "Processing new image"); + byte[] data = frame.getData(); + Size size = frame.getSize(); + int width = size.getWidth(); + int height = size.getHeight(); + int rot = getCorrectCameraOrientation(cameraView.getFacing(),frame.getRotation()); - mDecodeThreadPool.execute(() -> processNewFrame(data, width, height, rotationDegrees)); - } else { - mEncodeVideoThreadPool.execute(() -> recordNewFrame(data, width, height, rotationDegrees)); + if (!doingVideoProcessing) { + mDecodeThreadPool.execute(() -> processNewFrame(data, width, height, rot)); + } else { + mEncodeVideoThreadPool.execute(() -> recordNewFrame(data, width, height, rot)); + } + } } }); @@ -234,12 +248,10 @@ public void updateCamera () { switch (prefs.getCamera()) { case PreferenceManager.FRONT: - if (cameraView.getFacing() != CameraView.FACING_FRONT) - cameraView.setFacing(CameraView.FACING_FRONT); + cameraView.setFacing(Facing.FRONT); break; case PreferenceManager.BACK: - if (cameraView.getFacing() != CameraView.FACING_BACK) - cameraView.setFacing(CameraView.FACING_BACK); + cameraView.setFacing(Facing.BACK); break; default: // camera = null; @@ -321,8 +333,8 @@ private synchronized void processNewFrame (byte[] data, int width, int height, i data, width, height, - cameraView.getDefaultOrientation(), - cameraView.getFacing()); + rotationDegrees, + cameraView.getFacing()==Facing.FRONT); lastPic = data; @@ -349,12 +361,12 @@ private synchronized boolean recordVideo() { mtxVideoRotate = new Matrix(); - if (cameraView.getFacing() == CameraView.FACING_FRONT) { - mtxVideoRotate.postRotate(-cameraView.getDefaultOrientation()); + if (cameraView.getFacing() == Facing.FRONT) { + mtxVideoRotate.postRotate(-cameraView.getRotation()); mtxVideoRotate.postScale(-1, 1, cameraView.getWidth() / 2, cameraView.getHeight() / 2); } else - mtxVideoRotate.postRotate(cameraView.getDefaultOrientation()); + mtxVideoRotate.postRotate(cameraView.getRotation()); doingVideoProcessing = true; @@ -374,13 +386,10 @@ private synchronized boolean recordVideo() { public synchronized void stopCamera () { if (cameraView != null) { - cameraView.stop(); + cameraView.close(); } } - public int getCameraFacing() { - return cameraView.getFacing(); - } public void destroy () { @@ -391,7 +400,7 @@ public void destroy () stopCamera(); } - public int getCorrectCameraOrientation(int facing, int orientation) { + public int getCorrectCameraOrientation(Facing facing, int orientation) { int rotation = context.getWindowManager().getDefaultDisplay().getRotation(); int degrees = 0; @@ -416,7 +425,7 @@ public int getCorrectCameraOrientation(int facing, int orientation) { } int result; - if(facing == CameraView.FACING_FRONT){ + if(facing == Facing.FRONT){ result = (orientation + degrees) % 360; result = (360 - result) % 360; }else{ diff --git a/src/main/java/org/havenapp/main/sensors/motion/MotionDetector.java b/src/main/java/org/havenapp/main/sensors/motion/MotionDetector.java index 0fdac736..6dbf8dd7 100644 --- a/src/main/java/org/havenapp/main/sensors/motion/MotionDetector.java +++ b/src/main/java/org/havenapp/main/sensors/motion/MotionDetector.java @@ -12,7 +12,6 @@ import android.graphics.Matrix; import android.os.Handler; -import com.google.android.cameraview.CameraView; import org.havenapp.main.sensors.media.ImageCodec; @@ -84,7 +83,7 @@ public void detect(byte[] rawOldPic, int width, int height, int rotationDegrees, - int cameraFacing) { + boolean facingFront) { int[] newPicLuma = ImageCodec.N21toLuma(rawNewPic, width, height); if (rawOldPic != null) { @@ -118,7 +117,7 @@ public void detect(byte[] rawOldPic, Matrix mtx = new Matrix(); - if (cameraFacing == CameraView.FACING_FRONT) { + if (facingFront) { mtx.postRotate(-rotationDegrees); mtx.postScale(-1, 1, width / 2, height / 2); } diff --git a/src/main/java/org/havenapp/main/ui/CameraFragment.java b/src/main/java/org/havenapp/main/ui/CameraFragment.java index 90698b82..b60dd5b9 100644 --- a/src/main/java/org/havenapp/main/ui/CameraFragment.java +++ b/src/main/java/org/havenapp/main/ui/CameraFragment.java @@ -16,7 +16,7 @@ import android.widget.ImageView; import android.widget.TextView; -import com.google.android.cameraview.CameraView; +import com.otaliastudios.cameraview.CameraView; import org.havenapp.main.PreferenceManager; import org.havenapp.main.R; @@ -84,13 +84,6 @@ public void stopCamera () } } - /** - public void resetCamera () - { - stopCamera(); - initCamera(); - }**/ - public void initCamera () { diff --git a/src/main/res/layout/camera_fragment.xml b/src/main/res/layout/camera_fragment.xml index 083abd94..12a67110 100644 --- a/src/main/res/layout/camera_fragment.xml +++ b/src/main/res/layout/camera_fragment.xml @@ -5,7 +5,8 @@ xmlns:app="http://schemas.android.com/apk/res-auto" android:foreground="@color/translucentOverlay25"> - + app:useHighResPicture="false"/>--> + + + Date: Wed, 6 Feb 2019 13:19:10 -0500 Subject: [PATCH 2/4] don't record audio with the video camera --- src/main/java/org/havenapp/main/ui/CameraFragment.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/havenapp/main/ui/CameraFragment.java b/src/main/java/org/havenapp/main/ui/CameraFragment.java index b60dd5b9..49ee4ecb 100644 --- a/src/main/java/org/havenapp/main/ui/CameraFragment.java +++ b/src/main/java/org/havenapp/main/ui/CameraFragment.java @@ -16,7 +16,9 @@ import android.widget.ImageView; import android.widget.TextView; +import com.otaliastudios.cameraview.Audio; import com.otaliastudios.cameraview.CameraView; +import com.otaliastudios.cameraview.SizeSelector; import org.havenapp.main.PreferenceManager; import org.havenapp.main.R; @@ -63,9 +65,7 @@ public void onPause() { @Override public void onResume() { super.onResume(); - // if (cameraViewHolder == null) - initCamera(); - + initCamera(); cameraViewHolder.setMotionSensitivity(prefs.getCameraSensitivity()); } @@ -94,6 +94,7 @@ public void initCamera () //Uncomment to see the camera CameraView cameraView = getActivity().findViewById(R.id.camera_view); + cameraView.setAudio(Audio.OFF); if (cameraViewHolder == null) { cameraViewHolder = new CameraViewHolder(getActivity(), cameraView); From 4b808e6b6d2cbd4b653c727f8e659cb331e33d9f Mon Sep 17 00:00:00 2001 From: n8fr8 Date: Wed, 6 Feb 2019 17:07:42 -0500 Subject: [PATCH 3/4] more cleanly isolate notification channel code --- .../havenapp/main/service/MonitorService.java | 26 +++++++++++-------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/src/main/java/org/havenapp/main/service/MonitorService.java b/src/main/java/org/havenapp/main/service/MonitorService.java index 68621399..abe31765 100644 --- a/src/main/java/org/havenapp/main/service/MonitorService.java +++ b/src/main/java/org/havenapp/main/service/MonitorService.java @@ -11,8 +11,6 @@ import android.annotation.SuppressLint; -import android.app.NotificationChannel; -import android.app.NotificationManager; import android.app.PendingIntent; import android.app.Service; import android.content.Intent; @@ -26,6 +24,7 @@ import android.telephony.SmsManager; import android.text.TextUtils; +import androidx.annotation.RequiresApi; import androidx.core.app.NotificationCompat; import org.havenapp.main.HavenApp; @@ -57,8 +56,6 @@ public class MonitorService extends Service { /** * To show a notification on service start */ - private NotificationManager manager; - private NotificationChannel mChannel; private final static String channelId = "monitor_id"; private final static CharSequence channelName = "Haven notifications"; private final static String channelDescription= "Important messages from Haven"; @@ -129,16 +126,10 @@ public void onCreate() { mApp = (HavenApp)getApplication(); - manager = (NotificationManager)getSystemService(NOTIFICATION_SERVICE); mPrefs = new PreferenceManager(this); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - mChannel = new NotificationChannel(channelId, channelName, - NotificationManager.IMPORTANCE_HIGH); - mChannel.setDescription(channelDescription); - mChannel.setLightColor(Color.RED); - mChannel.setImportance(NotificationManager.IMPORTANCE_MIN); - manager.createNotificationChannel(mChannel); + setupNotificationChannel(); } startSensors(); @@ -153,6 +144,19 @@ public void onCreate() { wakeLock.acquire(); } + @RequiresApi(api = Build.VERSION_CODES.O) + private void setupNotificationChannel () + { + android.app.NotificationManager manager = (android.app.NotificationManager)getSystemService(NOTIFICATION_SERVICE); + android.app.NotificationChannel channel; + channel = new android.app.NotificationChannel(channelId, channelName, + android.app.NotificationManager.IMPORTANCE_HIGH); + channel.setDescription(channelDescription); + channel.setLightColor(Color.RED); + channel.setImportance(android.app.NotificationManager.IMPORTANCE_MIN); + manager.createNotificationChannel(channel); + } + public static MonitorService getInstance () { return sInstance; From 4aa51f7349cf99078924c8fdead95faeee5bcdd5 Mon Sep 17 00:00:00 2001 From: n8fr8 Date: Wed, 6 Feb 2019 17:07:52 -0500 Subject: [PATCH 4/4] RenderScript in AndroidX is making things crash; disable for now! - use a simple method for NV21 image conversation until RenderScriptX stops being crashy --- build.gradle | 7 ++--- .../main/sensors/motion/CameraViewHolder.java | 9 +++---- .../main/sensors/motion/MotionDetector.java | 26 ++++++++++++++----- 3 files changed, 28 insertions(+), 14 deletions(-) diff --git a/build.gradle b/build.gradle index edca2dda..952b1713 100644 --- a/build.gradle +++ b/build.gradle @@ -1,5 +1,5 @@ buildscript { - ext.kotlin_version = '1.3.0' + ext.kotlin_version = '1.3.20' repositories { google() jcenter() @@ -91,8 +91,9 @@ android { } multiDexEnabled true vectorDrawables.useSupportLibrary = true - renderscriptTargetApi 16 - renderscriptSupportModeEnabled true + + // renderscriptTargetApi 16 + // renderscriptSupportModeEnabled true ndk { abiFilters "armeabi", "armeabi-v7a", "x86" diff --git a/src/main/java/org/havenapp/main/sensors/motion/CameraViewHolder.java b/src/main/java/org/havenapp/main/sensors/motion/CameraViewHolder.java index 51fe280a..fb87d1c5 100644 --- a/src/main/java/org/havenapp/main/sensors/motion/CameraViewHolder.java +++ b/src/main/java/org/havenapp/main/sensors/motion/CameraViewHolder.java @@ -51,7 +51,6 @@ import java.util.concurrent.TimeUnit; import androidx.annotation.NonNull; -import androidx.renderscript.RenderScript; import io.github.silvaren.easyrs.tools.Nv21Image; @@ -107,7 +106,7 @@ public class CameraViewHolder { private File videoFile; //for managing bitmap processing - private RenderScript renderScript; + //private RenderScript renderScript; private ServiceConnection mConnection = new ServiceConnection() { @@ -128,12 +127,11 @@ public CameraViewHolder(Activity context, CameraView cameraView) { //super(context); this.context = context; this.cameraView = cameraView; - this.renderScript = RenderScript.create(context); // where context can be your activity, application, etc. + //this.renderScript = RenderScript.create(context); // where context can be your activity, application, etc. prefs = new PreferenceManager(context); task = new MotionDetector( - renderScript, updateHandler, motionSensitivity); @@ -287,7 +285,8 @@ public void updateCamera () private void recordNewFrame (byte[] data, int width, int height, int rotationDegrees) { - Bitmap bitmap = Nv21Image.nv21ToBitmap(renderScript, data, width, height); + Bitmap bitmap = MotionDetector.convertImage(data, width, height); + //Nv21Image.nv21ToBitmap(renderScript, data, width, height); bitmap = Bitmap.createBitmap(bitmap,0,0,width,height,mtxVideoRotate,true); diff --git a/src/main/java/org/havenapp/main/sensors/motion/MotionDetector.java b/src/main/java/org/havenapp/main/sensors/motion/MotionDetector.java index 6dbf8dd7..e3daa135 100644 --- a/src/main/java/org/havenapp/main/sensors/motion/MotionDetector.java +++ b/src/main/java/org/havenapp/main/sensors/motion/MotionDetector.java @@ -8,18 +8,21 @@ import android.graphics.Bitmap; +import android.graphics.BitmapFactory; import android.graphics.Color; +import android.graphics.ImageFormat; import android.graphics.Matrix; +import android.graphics.Rect; +import android.graphics.YuvImage; import android.os.Handler; import org.havenapp.main.sensors.media.ImageCodec; +import java.io.ByteArrayOutputStream; import java.util.ArrayList; import java.util.List; -import androidx.renderscript.RenderScript; -import io.github.silvaren.easyrs.tools.Nv21Image; /** * Task doing all image processing in backgrounds, @@ -41,7 +44,7 @@ public class MotionDetector { private IMotionDetector detector; - private RenderScript renderScript; + //private RenderScript renderScript; private int detectColor = Color.YELLOW; @@ -57,10 +60,10 @@ public void addListener(MotionListener listener) { } public MotionDetector( - RenderScript renderScript, + Handler updateHandler, int motionSensitivity) { - this.renderScript = renderScript; + // this.renderScript = renderScript; this.handler = updateHandler; this.motionSensitivity = motionSensitivity; detector = new LuminanceMotionDetector(); @@ -128,7 +131,8 @@ public void detect(byte[] rawOldPic, Bitmap newBitmap = Bitmap.createBitmap(Bitmap.createBitmap(newPic, width, height, Bitmap.Config.ARGB_4444), 0, 0, width, height, mtx, true); - Bitmap rawBitmap = Bitmap.createBitmap(Nv21Image.nv21ToBitmap(renderScript, rawNewPic, width, height),0,0,width,height,mtx,true); + Bitmap rawBitmap = convertImage(rawNewPic,width,height); + //Bitmap.createBitmap(Nv21Image.nv21ToBitmap(renderScript, rawNewPic, width, height),0,0,width,height,mtx,true); handler.post(() -> { for (MotionListener listener : listeners) { @@ -161,5 +165,15 @@ public void detect(byte[] rawOldPic, } + public static Bitmap convertImage (byte[] nv21bytearray, int width, int height) + { + YuvImage yuvImage = new YuvImage(nv21bytearray, ImageFormat.NV21, width, height, null); + ByteArrayOutputStream os = new ByteArrayOutputStream(); + yuvImage.compressToJpeg(new Rect(0, 0, width, height), 100, os); + byte[] jpegByteArray = os.toByteArray(); + Bitmap bitmap = BitmapFactory.decodeByteArray(jpegByteArray, 0, jpegByteArray.length); + return bitmap; + } + }