@@ -1,4 +1,4 @@ | |||
package com.example.ueberwachungssystem; | |||
package com.example.ueberwachungssystem.Detection; | |||
import android.util.Log; | |||
@@ -1,4 +1,4 @@ | |||
package com.example.ueberwachungssystem; | |||
package com.example.ueberwachungssystem.Detection; | |||
import androidx.annotation.NonNull; | |||
@@ -1,4 +1,4 @@ | |||
package com.example.ueberwachungssystem.VideoDetection; | |||
package com.example.ueberwachungssystem.Detection; | |||
import android.content.Context; | |||
import android.graphics.ImageFormat; | |||
@@ -15,12 +15,27 @@ import androidx.camera.view.PreviewView; | |||
import androidx.core.content.ContextCompat; | |||
import androidx.lifecycle.LifecycleOwner; | |||
import com.example.ueberwachungssystem.Detector; | |||
import com.google.common.util.concurrent.ListenableFuture; | |||
import java.nio.ByteBuffer; | |||
import java.util.concurrent.ExecutionException; | |||
/** | |||
* Video Detector inherits some methods from abstract Detector class (more info there) | |||
* | |||
* | |||
* USE FROM MAIN ACTIVITY: | |||
* | |||
* VideoDetector vd = new VideoDetector(this); | |||
* vd.setPreview(previewView); //THIS IS OPTIONAL! | |||
* vd.setOnDetectionListener(new Detector.OnDetectionListener{...}); | |||
* vd.startDetection(); | |||
* vd.stopDetection | |||
* | |||
* */ | |||
@ExperimentalGetImage | |||
public class VideoDetector extends Detector { | |||
@@ -33,19 +48,24 @@ public class VideoDetector extends Detector { | |||
private PreviewView previewView = null; | |||
// Detect Violation | |||
private static final float PIXEL_THRESHOLD = 30f; // Luminosity (brightness channel of YUV_420_888) | |||
private static final float ALARM_THRESHOLD = 1f; // Percent of pixels changed | |||
private static final float ALARM_THRESHOLD = 0.2f; // Percent of pixels changed | |||
private ByteBuffer previousBuffer = null; | |||
/** Constructor */ | |||
/** | |||
* Constructor | |||
* @param context: the context of calling activity (usually "this") | |||
* */ | |||
public VideoDetector(Context context) { | |||
super(); | |||
this.context = context; | |||
} | |||
/** Starts Video Detection */ | |||
/** | |||
* Starts the Video Detection | |||
* */ | |||
@Override | |||
public void startDetection() { | |||
if (isDetectionRunning) | |||
@@ -56,7 +76,7 @@ public class VideoDetector extends Detector { | |||
cameraProviderFuture.addListener(() -> { | |||
try { | |||
cameraProvider = cameraProviderFuture.get(); | |||
bindLuminosityAnalysis(cameraProvider); | |||
bindAnalysis(cameraProvider); | |||
isDetectionRunning = true; | |||
previousBuffer = null; | |||
} catch (ExecutionException | InterruptedException e) { | |||
@@ -66,7 +86,9 @@ public class VideoDetector extends Detector { | |||
} | |||
/** Stops Video Detection */ | |||
/** | |||
* Stops the Video Detection | |||
* */ | |||
@Override | |||
public void stopDetection() { | |||
if (!isDetectionRunning) | |||
@@ -76,14 +98,20 @@ public class VideoDetector extends Detector { | |||
} | |||
/** Set PreviewView to show Image */ | |||
/** | |||
* Set PreviewView to show video feed while detecting | |||
* this is optional and does not need to be called | |||
* */ | |||
public void setPreviewView(PreviewView previewView) { | |||
this.previewView = previewView; | |||
} | |||
/** Binds the Luminosity Analyzer (configure and run Analysis) */ | |||
private void bindLuminosityAnalysis(@NonNull ProcessCameraProvider cameraProvider) { | |||
/** | |||
* Binds the Luminosity Analyzer (configure and run Analysis) | |||
* @param cameraProvider: CameraProvider of Context passed by Constructor | |||
* */ | |||
private void bindAnalysis(@NonNull ProcessCameraProvider cameraProvider) { | |||
// Configure and create Image Analysis | |||
ImageAnalysis.Builder builder = new ImageAnalysis.Builder(); | |||
builder.setTargetResolution(new Size(640, 480)); | |||
@@ -122,7 +150,10 @@ public class VideoDetector extends Detector { | |||
/** Calculate Amount of Pixels changed */ | |||
/** | |||
* Calculate Amount of Pixels changed using a threshold | |||
* @param image | |||
* */ | |||
private int getChangedPixelCount(Image image) { | |||
Image.Plane[] planes = image.getPlanes(); | |||
ByteBuffer buffer = planes[0].getBuffer(); |
@@ -0,0 +1,147 @@ | |||
package com.example.ueberwachungssystem; | |||
import android.annotation.SuppressLint; | |||
import android.content.Context; | |||
import android.content.pm.PackageManager; | |||
import android.media.MediaPlayer; | |||
import android.view.Surface; | |||
import android.widget.Toast; | |||
import android.widget.VideoView; | |||
import androidx.annotation.NonNull; | |||
import androidx.annotation.Nullable; | |||
import androidx.camera.core.CameraSelector; | |||
import androidx.camera.core.Preview; | |||
import androidx.camera.core.VideoCapture; | |||
import androidx.camera.lifecycle.ProcessCameraProvider; | |||
import androidx.camera.view.PreviewView; | |||
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.util.concurrent.ExecutionException; | |||
public class DetectionRecorder { | |||
private final Context context; | |||
private ProcessCameraProvider cameraProvider; | |||
private VideoCapture videoCapture = null; | |||
private PreviewView previewView = null; | |||
private boolean isRunning = false; | |||
private boolean isVideoPlaying = false; | |||
// Constructor | |||
public DetectionRecorder(Context context) { | |||
this.context = context; | |||
} | |||
public void start() { | |||
if (isRunning) | |||
return; | |||
isRunning = true; | |||
// Request Camera Provider | |||
final ListenableFuture<ProcessCameraProvider> cameraProviderFuture = ProcessCameraProvider.getInstance(context); | |||
//Check for Camera availability | |||
cameraProviderFuture.addListener(() -> { | |||
try { | |||
cameraProvider = cameraProviderFuture.get(); | |||
startCameraX(cameraProvider); | |||
} catch (ExecutionException | InterruptedException e) { | |||
// No errors need to be handled for this Future. This should never be reached. | |||
} | |||
}, ContextCompat.getMainExecutor(context)); | |||
} | |||
@SuppressLint("RestrictedApi") | |||
public void stop() { | |||
if (!isRunning) | |||
return; | |||
videoCapture.stopRecording(); | |||
cameraProvider.unbind(videoCapture); | |||
isRunning = false; | |||
} | |||
@SuppressLint("RestrictedApi") | |||
private void startCameraX(ProcessCameraProvider cameraProvider) { | |||
//cameraProvider.unbindAll(); | |||
CameraSelector cameraSelector = new CameraSelector.Builder() | |||
.requireLensFacing(CameraSelector.LENS_FACING_BACK) | |||
.build(); | |||
// Preview Use Case | |||
Preview preview = new Preview.Builder().build(); | |||
if (previewView != null) | |||
preview.setSurfaceProvider(previewView.getSurfaceProvider()); | |||
// Video Capture Use Case | |||
videoCapture = new VideoCapture.Builder() | |||
.setVideoFrameRate(30) | |||
.setTargetRotation(Surface.ROTATION_0) | |||
.build(); | |||
cameraProvider.bindToLifecycle((LifecycleOwner) context, cameraSelector, preview, videoCapture); | |||
File dir = context.getFilesDir(); | |||
String filename = "recording"; | |||
String vidFilePath = dir.getAbsolutePath() + "/" + filename + ".mp4"; | |||
File vidFile = new File(vidFilePath); | |||
if (ActivityCompat.checkSelfPermission(context, android.Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) { | |||
// TODO: Consider calling | |||
// ActivityCompat#requestPermissions | |||
// here to request the missing permissions, and then overriding | |||
// public void onRequestPermissionsResult(int requestCode, String[] permissions, | |||
// int[] grantResults) | |||
// to handle the case where the user grants the permission. See the documentation | |||
// for ActivityCompat#requestPermissions for more details. | |||
return; | |||
} | |||
videoCapture.startRecording( | |||
new VideoCapture.OutputFileOptions.Builder(vidFile).build(), | |||
context.getMainExecutor(), | |||
new VideoCapture.OnVideoSavedCallback() { | |||
@Override | |||
public void onVideoSaved(@NonNull VideoCapture.OutputFileResults outputFileResults) { | |||
Toast.makeText(context, "recording saved", Toast.LENGTH_SHORT).show(); | |||
} | |||
@Override | |||
public void onError(int videoCaptureError, @NonNull String message, @Nullable Throwable cause) { | |||
Toast.makeText(context, "recording failed", Toast.LENGTH_SHORT).show(); | |||
} | |||
} | |||
); | |||
} | |||
/** Set PreviewView to show Image */ | |||
public void setPreviewView(PreviewView previewView) { | |||
this.previewView = previewView; | |||
} | |||
private void playAudio() { | |||
MediaPlayer mp = new MediaPlayer(); | |||
try { | |||
mp.setDataSource(context.getFilesDir() + "/audio.gpp"); | |||
mp.prepare(); | |||
mp.start(); | |||
} catch (Exception e) { | |||
e.printStackTrace(); | |||
} | |||
} | |||
public void playVideo(VideoView videoView) { | |||
if (isVideoPlaying) | |||
return; | |||
videoView.setVideoPath(context.getFilesDir() + "/recording.mp4"); | |||
videoView.start(); | |||
} | |||
} |
@@ -10,16 +10,15 @@ import androidx.camera.core.ExperimentalGetImage; | |||
import android.Manifest; | |||
import android.content.pm.PackageManager; | |||
import android.os.Bundle; | |||
import android.view.SurfaceView; | |||
import android.view.View; | |||
import android.widget.TextView; | |||
import android.widget.Toast; | |||
import android.widget.ToggleButton; | |||
import android.widget.VideoView; | |||
import com.example.ueberwachungssystem.Detection.VideoDetector; | |||
import java.io.File; | |||
import java.net.URISyntaxException; | |||
import java.util.Arrays; | |||
@ExperimentalGetImage | |||
public class MainActivity extends AppCompatActivity { | |||
@@ -33,7 +32,6 @@ public class MainActivity extends AppCompatActivity { | |||
setContentView(R.layout.activity_main); | |||
TextView textView = findViewById(R.id.textView); | |||
SurfaceView surfaceView = findViewById(R.id.surfaceView); | |||
VideoView videoView = findViewById(R.id.videoView); | |||
PreviewView previewView = findViewById(R.id.previewView); | |||
@@ -41,8 +39,9 @@ public class MainActivity extends AppCompatActivity { | |||
RecorderX recorderX = new RecorderX(this); | |||
//recorderX.setPreviewView(previewView); | |||
DetectionRecorder detectionRecorder = new DetectionRecorder(this); | |||
detectionRecorder.setPreviewView(previewView); | |||
ToggleButton toggleButton = findViewById(R.id.previewButton); | |||
toggleButton.setOnClickListener(new View.OnClickListener() { | |||
@@ -52,16 +51,13 @@ public class MainActivity extends AppCompatActivity { | |||
if (isRecordVideoAllowed() && toggleButton.isChecked()) | |||
{ | |||
try { | |||
recorderX.startRecording(); | |||
} catch (URISyntaxException e) { | |||
throw new RuntimeException(e); | |||
} | |||
detectionRecorder.playVideo(videoView); | |||
//detectionRecorder.start(); | |||
} | |||
else { | |||
recorderX.stopRecording(); | |||
detectionRecorder.stop(); | |||
File[] files = directory.listFiles(); | |||
textView.setText(Arrays.toString(files)); | |||
//textView.setText(Arrays.toString(files)); | |||
} | |||
} | |||
}); |
@@ -1,114 +0,0 @@ | |||
package com.example.ueberwachungssystem; | |||
import android.app.Activity; | |||
import android.content.Context; | |||
import android.hardware.Camera; | |||
import android.media.CamcorderProfile; | |||
import android.media.MediaPlayer; | |||
import android.media.MediaRecorder; | |||
import android.view.SurfaceHolder; | |||
import android.view.SurfaceView; | |||
import android.view.WindowManager; | |||
import android.widget.VideoView; | |||
import java.io.IOException; | |||
public class Recorder { | |||
private final Context context; | |||
private Camera camera; | |||
private MediaRecorder mediaRecorder = null; | |||
private SurfaceView surfaceView; | |||
private static final int SENSOR_ORIENTATION_DEFAULT_DEGREES = 90; | |||
private static final int SENSOR_ORIENTATION_INVERSE_DEGREES = 270; | |||
public Recorder (Context context) { | |||
this.context = context; | |||
this.surfaceView = new SurfaceView(context); | |||
} | |||
public void startRecording() { | |||
try { | |||
// Open the camera | |||
camera = Camera.open(); | |||
camera.setPreviewDisplay(surfaceView.getHolder()); | |||
camera.startPreview(); | |||
camera.unlock(); | |||
// Create a new MediaRecorder instance | |||
mediaRecorder = new MediaRecorder(); | |||
// Set the camera as the video source | |||
mediaRecorder.setCamera(camera); | |||
// Set the audio and video source | |||
mediaRecorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER); | |||
mediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA); | |||
CamcorderProfile camcorderProfile = CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH); | |||
mediaRecorder.setProfile(camcorderProfile); | |||
// Set the output file path | |||
mediaRecorder.setOutputFile(context.getFilesDir() + "/video.mp4"); | |||
mediaRecorder.prepare(); | |||
mediaRecorder.start(); | |||
} catch (IOException e) { | |||
e.printStackTrace(); | |||
} | |||
} | |||
public void stopRecording() { | |||
if (mediaRecorder != null) { | |||
try { | |||
mediaRecorder.stop(); | |||
mediaRecorder.reset(); | |||
mediaRecorder.release(); | |||
mediaRecorder = null; | |||
} catch (RuntimeException e) { | |||
// RuntimeException may be thrown if the MediaRecorder is in an invalid state | |||
e.printStackTrace(); | |||
} | |||
if (camera != null) { | |||
try { | |||
camera.reconnect(); | |||
camera.stopPreview(); | |||
camera.lock(); | |||
camera.release(); | |||
camera = null; | |||
} catch (IOException e) { | |||
e.printStackTrace(); | |||
} | |||
} | |||
} | |||
} | |||
public void setSurfaceView(SurfaceView surfaceView) { | |||
this.surfaceView = surfaceView; | |||
} | |||
private void playAudio() { | |||
MediaPlayer mp = new MediaPlayer(); | |||
try { | |||
mp.setDataSource(context.getFilesDir() + "/audio.gpp"); | |||
mp.prepare(); | |||
mp.start(); | |||
} catch (Exception e) { | |||
e.printStackTrace(); | |||
} | |||
} | |||
public void playVideo(VideoView videoView) { | |||
videoView.setVideoPath(context.getFilesDir() + "/video.mp4"); | |||
videoView.start(); | |||
} | |||
} |
@@ -1,153 +0,0 @@ | |||
package com.example.ueberwachungssystem; | |||
import android.annotation.SuppressLint; | |||
import android.content.ContentValues; | |||
import android.content.Context; | |||
import android.media.MediaPlayer; | |||
import android.net.Uri; | |||
import android.provider.MediaStore; | |||
import android.util.Log; | |||
import android.widget.Toast; | |||
import android.widget.VideoView; | |||
import androidx.camera.core.Camera; | |||
import androidx.camera.core.CameraSelector; | |||
import androidx.camera.core.Preview; | |||
import androidx.camera.lifecycle.ProcessCameraProvider; | |||
import androidx.camera.video.FallbackStrategy; | |||
import androidx.camera.video.MediaStoreOutputOptions; | |||
import androidx.camera.video.Quality; | |||
import androidx.camera.video.QualitySelector; | |||
import androidx.camera.video.Recorder; | |||
import androidx.camera.video.Recording; | |||
import androidx.camera.video.VideoCapture; | |||
import androidx.camera.video.VideoRecordEvent; | |||
import androidx.camera.view.PreviewView; | |||
import androidx.core.content.ContextCompat; | |||
import androidx.core.util.Consumer; | |||
import androidx.lifecycle.LifecycleOwner; | |||
import com.google.common.util.concurrent.ListenableFuture; | |||
import java.net.URISyntaxException; | |||
import java.util.concurrent.ExecutionException; | |||
public class RecorderX { | |||
private final Context context; | |||
private PreviewView previewView = null; | |||
private ProcessCameraProvider cameraProvider; | |||
private Recording recording = null; | |||
public RecorderX(Context context) { | |||
this.context = context; | |||
} | |||
@SuppressLint("MissingPermission") | |||
public void startRecording() throws URISyntaxException { | |||
final ListenableFuture<ProcessCameraProvider> cameraProviderFuture = ProcessCameraProvider.getInstance(context); | |||
try { | |||
cameraProvider = cameraProviderFuture.get(); | |||
} catch (ExecutionException | InterruptedException ignored) { | |||
} | |||
QualitySelector qualitySelector = QualitySelector | |||
.from(Quality.HD, FallbackStrategy.higherQualityOrLowerThan(Quality.SD)); | |||
Recorder.Builder recorderBuilder = new Recorder.Builder(); | |||
recorderBuilder.setQualitySelector(qualitySelector); | |||
Recorder recorder = recorderBuilder.build(); | |||
VideoCapture<Recorder> videoCapture = VideoCapture.withOutput(recorder); | |||
// Create Preview | |||
Preview preview = new Preview.Builder().build(); | |||
// Specify which Camera to use | |||
CameraSelector cameraSelector = new CameraSelector.Builder().requireLensFacing(CameraSelector.LENS_FACING_BACK).build(); | |||
// Update PreviewView if set | |||
if (previewView != null) | |||
preview.setSurfaceProvider(previewView.getSurfaceProvider()); | |||
try { | |||
Camera camera = cameraProvider.bindToLifecycle((LifecycleOwner) context, cameraSelector, videoCapture, preview); | |||
} catch (Exception e) { | |||
Log.e("Error", "Use case binding failed", e); | |||
} | |||
String name = "recording.mp4"; | |||
Uri filesDirURI = Uri.fromFile(context.getFilesDir()); | |||
ContentValues contentValues = new ContentValues(); | |||
contentValues.put(MediaStore.Video.Media.DISPLAY_NAME, name); | |||
MediaStoreOutputOptions mediaStoreOutput = new MediaStoreOutputOptions | |||
.Builder(context.getContentResolver(), filesDirURI) | |||
.setContentValues(contentValues) | |||
.build(); | |||
Consumer<VideoRecordEvent> recordingListener = new Consumer<VideoRecordEvent>() { | |||
@Override | |||
public void accept(VideoRecordEvent videoRecordEvent) { | |||
if (videoRecordEvent instanceof VideoRecordEvent.Start) { | |||
Toast.makeText(context, "Carture started", Toast.LENGTH_SHORT).show(); | |||
} | |||
else if (videoRecordEvent instanceof VideoRecordEvent.Finalize) { | |||
VideoRecordEvent.Finalize finalize = (VideoRecordEvent.Finalize) videoRecordEvent; | |||
if (!finalize.hasError()) { | |||
Toast.makeText(context, "Carture succeeded", Toast.LENGTH_SHORT).show(); | |||
} | |||
else { | |||
recording.close(); | |||
recording = null; | |||
Toast.makeText(context, "Carture failed", Toast.LENGTH_SHORT).show(); | |||
} | |||
} | |||
} | |||
}; | |||
recording = videoCapture.getOutput() | |||
.prepareRecording(context, mediaStoreOutput) | |||
.withAudioEnabled() | |||
.start(ContextCompat.getMainExecutor(context), recordingListener); | |||
} | |||
public void stopRecording() { | |||
recording.stop(); | |||
} | |||
/** Set PreviewView to show Image */ | |||
public void setPreviewView(PreviewView previewView) { | |||
this.previewView = previewView; | |||
} | |||
private void playAudio() { | |||
MediaPlayer mp = new MediaPlayer(); | |||
try { | |||
mp.setDataSource(context.getFilesDir() + "/audio.gpp"); | |||
mp.prepare(); | |||
mp.start(); | |||
} catch (Exception e) { | |||
e.printStackTrace(); | |||
} | |||
} | |||
public void playVideo(VideoView videoView) { | |||
videoView.setVideoPath(context.getFilesDir() + "/video.mp4"); | |||
videoView.start(); | |||
} | |||
} |
@@ -27,10 +27,6 @@ | |||
android:layout_height="wrap_content" | |||
android:text="ToggleButton" /> | |||
<SurfaceView | |||
android:id="@+id/surfaceView" | |||
android:layout_width="match_parent" | |||
android:layout_height="200dp" /> | |||
<androidx.camera.view.PreviewView | |||
android:id="@+id/previewView" |