package com.example.ueberwachungssystem; | |||||
package com.example.ueberwachungssystem.Detection; | |||||
import android.util.Log; | import android.util.Log; | ||||
package com.example.ueberwachungssystem; | |||||
package com.example.ueberwachungssystem.Detection; | |||||
import androidx.annotation.NonNull; | import androidx.annotation.NonNull; | ||||
package com.example.ueberwachungssystem.VideoDetection; | |||||
package com.example.ueberwachungssystem.Detection; | |||||
import android.content.Context; | import android.content.Context; | ||||
import android.graphics.ImageFormat; | import android.graphics.ImageFormat; | ||||
import androidx.core.content.ContextCompat; | import androidx.core.content.ContextCompat; | ||||
import androidx.lifecycle.LifecycleOwner; | import androidx.lifecycle.LifecycleOwner; | ||||
import com.example.ueberwachungssystem.Detector; | |||||
import com.google.common.util.concurrent.ListenableFuture; | import com.google.common.util.concurrent.ListenableFuture; | ||||
import java.nio.ByteBuffer; | import java.nio.ByteBuffer; | ||||
import java.util.concurrent.ExecutionException; | 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 | @ExperimentalGetImage | ||||
public class VideoDetector extends Detector { | public class VideoDetector extends Detector { | ||||
private PreviewView previewView = null; | private PreviewView previewView = null; | ||||
// Detect Violation | // Detect Violation | ||||
private static final float PIXEL_THRESHOLD = 30f; // Luminosity (brightness channel of YUV_420_888) | 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; | private ByteBuffer previousBuffer = null; | ||||
/** Constructor */ | |||||
/** | |||||
* Constructor | |||||
* @param context: the context of calling activity (usually "this") | |||||
* */ | |||||
public VideoDetector(Context context) { | public VideoDetector(Context context) { | ||||
super(); | super(); | ||||
this.context = context; | this.context = context; | ||||
} | } | ||||
/** Starts Video Detection */ | |||||
/** | |||||
* Starts the Video Detection | |||||
* */ | |||||
@Override | @Override | ||||
public void startDetection() { | public void startDetection() { | ||||
if (isDetectionRunning) | if (isDetectionRunning) | ||||
cameraProviderFuture.addListener(() -> { | cameraProviderFuture.addListener(() -> { | ||||
try { | try { | ||||
cameraProvider = cameraProviderFuture.get(); | cameraProvider = cameraProviderFuture.get(); | ||||
bindLuminosityAnalysis(cameraProvider); | |||||
bindAnalysis(cameraProvider); | |||||
isDetectionRunning = true; | isDetectionRunning = true; | ||||
previousBuffer = null; | previousBuffer = null; | ||||
} catch (ExecutionException | InterruptedException e) { | } catch (ExecutionException | InterruptedException e) { | ||||
} | } | ||||
/** Stops Video Detection */ | |||||
/** | |||||
* Stops the Video Detection | |||||
* */ | |||||
@Override | @Override | ||||
public void stopDetection() { | public void stopDetection() { | ||||
if (!isDetectionRunning) | if (!isDetectionRunning) | ||||
} | } | ||||
/** 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) { | public void setPreviewView(PreviewView previewView) { | ||||
this.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 | // Configure and create Image Analysis | ||||
ImageAnalysis.Builder builder = new ImageAnalysis.Builder(); | ImageAnalysis.Builder builder = new ImageAnalysis.Builder(); | ||||
builder.setTargetResolution(new Size(640, 480)); | builder.setTargetResolution(new Size(640, 480)); | ||||
/** Calculate Amount of Pixels changed */ | |||||
/** | |||||
* Calculate Amount of Pixels changed using a threshold | |||||
* @param image | |||||
* */ | |||||
private int getChangedPixelCount(Image image) { | private int getChangedPixelCount(Image image) { | ||||
Image.Plane[] planes = image.getPlanes(); | Image.Plane[] planes = image.getPlanes(); | ||||
ByteBuffer buffer = planes[0].getBuffer(); | ByteBuffer buffer = planes[0].getBuffer(); |
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(); | |||||
} | |||||
} |
import android.Manifest; | import android.Manifest; | ||||
import android.content.pm.PackageManager; | import android.content.pm.PackageManager; | ||||
import android.os.Bundle; | import android.os.Bundle; | ||||
import android.view.SurfaceView; | |||||
import android.view.View; | import android.view.View; | ||||
import android.widget.TextView; | import android.widget.TextView; | ||||
import android.widget.Toast; | import android.widget.Toast; | ||||
import android.widget.ToggleButton; | import android.widget.ToggleButton; | ||||
import android.widget.VideoView; | import android.widget.VideoView; | ||||
import com.example.ueberwachungssystem.Detection.VideoDetector; | |||||
import java.io.File; | import java.io.File; | ||||
import java.net.URISyntaxException; | |||||
import java.util.Arrays; | |||||
@ExperimentalGetImage | @ExperimentalGetImage | ||||
public class MainActivity extends AppCompatActivity { | public class MainActivity extends AppCompatActivity { | ||||
setContentView(R.layout.activity_main); | setContentView(R.layout.activity_main); | ||||
TextView textView = findViewById(R.id.textView); | TextView textView = findViewById(R.id.textView); | ||||
SurfaceView surfaceView = findViewById(R.id.surfaceView); | |||||
VideoView videoView = findViewById(R.id.videoView); | VideoView videoView = findViewById(R.id.videoView); | ||||
PreviewView previewView = findViewById(R.id.previewView); | PreviewView previewView = findViewById(R.id.previewView); | ||||
RecorderX recorderX = new RecorderX(this); | |||||
//recorderX.setPreviewView(previewView); | |||||
DetectionRecorder detectionRecorder = new DetectionRecorder(this); | |||||
detectionRecorder.setPreviewView(previewView); | |||||
ToggleButton toggleButton = findViewById(R.id.previewButton); | ToggleButton toggleButton = findViewById(R.id.previewButton); | ||||
toggleButton.setOnClickListener(new View.OnClickListener() { | toggleButton.setOnClickListener(new View.OnClickListener() { | ||||
if (isRecordVideoAllowed() && toggleButton.isChecked()) | if (isRecordVideoAllowed() && toggleButton.isChecked()) | ||||
{ | { | ||||
try { | |||||
recorderX.startRecording(); | |||||
} catch (URISyntaxException e) { | |||||
throw new RuntimeException(e); | |||||
} | |||||
detectionRecorder.playVideo(videoView); | |||||
//detectionRecorder.start(); | |||||
} | } | ||||
else { | else { | ||||
recorderX.stopRecording(); | |||||
detectionRecorder.stop(); | |||||
File[] files = directory.listFiles(); | File[] files = directory.listFiles(); | ||||
textView.setText(Arrays.toString(files)); | |||||
//textView.setText(Arrays.toString(files)); | |||||
} | } | ||||
} | } | ||||
}); | }); |
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(); | |||||
} | |||||
} |
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(); | |||||
} | |||||
} |
android:layout_height="wrap_content" | android:layout_height="wrap_content" | ||||
android:text="ToggleButton" /> | android:text="ToggleButton" /> | ||||
<SurfaceView | |||||
android:id="@+id/surfaceView" | |||||
android:layout_width="match_parent" | |||||
android:layout_height="200dp" /> | |||||
<androidx.camera.view.PreviewView | <androidx.camera.view.PreviewView | ||||
android:id="@+id/previewView" | android:id="@+id/previewView" |