Skip to content

Commit

Permalink
Merge pull request #361 from guardianproject/dev_new_cameraview
Browse files Browse the repository at this point in the history
improved cameraview
  • Loading branch information
n8fr8 authored Feb 7, 2019
2 parents a51704c + 4aa51f7 commit 2be8c80
Show file tree
Hide file tree
Showing 6 changed files with 114 additions and 71 deletions.
13 changes: 8 additions & 5 deletions build.gradle
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
buildscript {
ext.kotlin_version = '1.3.0'
ext.kotlin_version = '1.3.20'
repositories {
google()
jcenter()
Expand Down Expand Up @@ -91,8 +91,9 @@ android {
}
multiDexEnabled true
vectorDrawables.useSupportLibrary = true
renderscriptTargetApi 16
renderscriptSupportModeEnabled true

// renderscriptTargetApi 16
// renderscriptSupportModeEnabled true

ndk {
abiFilters "armeabi", "armeabi-v7a", "x86"
Expand Down Expand Up @@ -149,15 +150,14 @@ 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'
implementation 'com.googlecode.libphonenumber:libphonenumber:8.10.4'
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'
Expand All @@ -180,4 +180,7 @@ dependencies {

// 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'
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -46,7 +50,7 @@
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import androidx.renderscript.RenderScript;
import androidx.annotation.NonNull;

import io.github.silvaren.easyrs.tools.Nv21Image;

Expand Down Expand Up @@ -102,7 +106,7 @@ public class CameraViewHolder {
private File videoFile;

//for managing bitmap processing
private RenderScript renderScript;
//private RenderScript renderScript;

private ServiceConnection mConnection = new ServiceConnection() {

Expand All @@ -123,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);

Expand Down Expand Up @@ -202,28 +205,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));
}
}
}
});

Expand All @@ -234,12 +246,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;
Expand Down Expand Up @@ -275,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);

Expand Down Expand Up @@ -321,8 +332,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;

Expand All @@ -349,12 +360,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;

Expand All @@ -374,13 +385,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 ()
{
Expand All @@ -391,7 +399,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;
Expand All @@ -416,7 +424,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{
Expand Down
31 changes: 22 additions & 9 deletions src/main/java/org/havenapp/main/sensors/motion/MotionDetector.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +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 com.google.android.cameraview.CameraView;

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,
Expand All @@ -42,7 +44,7 @@ public class MotionDetector {

private IMotionDetector detector;

private RenderScript renderScript;
//private RenderScript renderScript;

private int detectColor = Color.YELLOW;

Expand All @@ -58,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();
Expand All @@ -84,7 +86,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) {
Expand Down Expand Up @@ -118,7 +120,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);
}
Expand All @@ -129,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) {
Expand Down Expand Up @@ -162,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;
}


}
26 changes: 15 additions & 11 deletions src/main/java/org/havenapp/main/service/MonitorService.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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";
Expand Down Expand Up @@ -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();
Expand All @@ -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;
Expand Down
Loading

0 comments on commit 2be8c80

Please sign in to comment.