Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

video recording support in logging #225

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 69 additions & 1 deletion android/app/src/main/java/org/openbot/common/CameraFragment.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,14 @@
import android.annotation.SuppressLint;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.util.Size;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;
import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.annotation.NonNull;
Expand All @@ -17,14 +20,20 @@
import androidx.camera.core.ImageAnalysis;
import androidx.camera.core.ImageProxy;
import androidx.camera.core.Preview;
import androidx.camera.core.VideoCapture;
import androidx.camera.lifecycle.ProcessCameraProvider;
import androidx.camera.view.PreviewView;
import androidx.core.content.ContextCompat;
import androidx.viewbinding.ViewBinding;
import com.google.common.util.concurrent.ListenableFuture;
import java.io.File;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import org.jetbrains.annotations.NotNull;
import org.openbot.R;
import org.openbot.env.ImageUtils;
import org.openbot.utils.Constants;
Expand All @@ -44,6 +53,7 @@ public abstract class CameraFragment extends ControlsFragment {
private YuvToRgbConverter converter;
private Bitmap bitmapBuffer;
private int rotationDegrees;
private VideoCapture videoCapture;

protected View inflateFragment(int resId, LayoutInflater inflater, ViewGroup container) {
return addCamera(inflater.inflate(resId, container, false), inflater, container);
Expand All @@ -60,6 +70,7 @@ private View addCamera(View view, LayoutInflater inflater, ViewGroup container)

previewView = cameraView.findViewById(R.id.viewFinder);
rootView.addView(view);
videoCapture = new VideoCapture.Builder().build();

if (!PermissionUtils.hasCameraPermission(requireActivity())) {
requestPermissionLauncherCamera.launch(Constants.PERMISSION_CAMERA);
Expand Down Expand Up @@ -130,7 +141,7 @@ private void bindCameraUseCases() {
try {
if (cameraProvider != null) {
cameraProvider.unbindAll();
cameraProvider.bindToLifecycle(this, cameraSelector, preview, imageAnalysis);
cameraProvider.bindToLifecycle(this, cameraSelector, preview, imageAnalysis, videoCapture);
}
} catch (Exception e) {
Timber.e("Use case binding failed: %s", e.toString());
Expand Down Expand Up @@ -188,5 +199,62 @@ public void setAnalyserResolution(Size resolutionSize) {
bindCameraUseCases();
}

@SuppressLint("RestrictedApi")
public void startVideoRecording() {
videoCapture = new VideoCapture.Builder().build();
bindCameraUseCases();
String outputDirectory =
Environment.getExternalStorageDirectory().getAbsolutePath()
+ File.separator
+ getString(R.string.app_name)
+ File.separator
+ new SimpleDateFormat("yyyyMMdd", Locale.getDefault()).format(new Date())
+ File.separator
+ "videos";
final File myDir = new File(outputDirectory);

if (!myDir.exists()) {
if (!myDir.mkdirs()) {
Timber.i("Make dir failed");
}
}

File videoFile =
new File(
outputDirectory,
new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault())
.format(System.currentTimeMillis())
+ ".mp4");
VideoCapture.OutputFileOptions outputOptions =
new VideoCapture.OutputFileOptions.Builder(videoFile).build();

videoCapture.startRecording(
outputOptions,
ContextCompat.getMainExecutor(requireContext()),
new VideoCapture.OnVideoSavedCallback() {
@Override
public void onVideoSaved(
@NonNull @NotNull VideoCapture.OutputFileResults outputFileResults) {
Uri savedUri = Uri.fromFile(videoFile);
Toast.makeText(
requireContext(), "Video capture succeeded:" + savedUri, Toast.LENGTH_SHORT)
.show();
}

@Override
public void onError(
int videoCaptureError,
@NonNull @NotNull String message,
@Nullable @org.jetbrains.annotations.Nullable Throwable cause) {
Timber.e("Video capture failed: " + message);
}
});
}

@SuppressLint("RestrictedApi")
public void stopVideoRecording() {
videoCapture.stopRecording();
}

protected abstract void processFrame(Bitmap image, ImageProxy imageProxy);
}
Original file line number Diff line number Diff line change
Expand Up @@ -308,12 +308,15 @@ private void startLogging() {
Timber.e(e, "Got interrupted.");
}
});
if (binding.videoCaptureCheckBox.isChecked()) startVideoRecording();
}

private void stopLogging() {
if (sensorConnection != null) requireActivity().unbindService(sensorConnection);
requireActivity().stopService(intentSensorService);

if (binding.videoCaptureCheckBox.isChecked()) stopVideoRecording();

// Pack and upload the collected data
runInBackground(
() -> {
Expand Down
2 changes: 1 addition & 1 deletion android/app/src/main/java/org/openbot/utils/Constants.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public class Constants {
public static final String PERMISSION_AUDIO = Manifest.permission.RECORD_AUDIO;

public static final String[] PERMISSIONS_LOGGING =
new String[] {PERMISSION_CAMERA, PERMISSION_STORAGE, PERMISSION_LOCATION};
new String[] {PERMISSION_CAMERA, PERMISSION_STORAGE, PERMISSION_AUDIO, PERMISSION_LOCATION};
public static final String[] PERMISSIONS_CONTROLLER =
new String[] {PERMISSION_CAMERA, PERMISSION_AUDIO, PERMISSION_LOCATION};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,10 @@ public static boolean hasAudioPermission(Activity activity) {

public static boolean hasLoggingPermissions(Activity activity) {
return hasPermissions(
activity, new String[] {PERMISSION_CAMERA, PERMISSION_STORAGE, PERMISSION_LOCATION});
activity,
new String[] {
PERMISSION_CAMERA, PERMISSION_AUDIO, PERMISSION_STORAGE, PERMISSION_LOCATION
});
}

public static boolean hasControllerPermissions(Activity activity) {
Expand Down
16 changes: 13 additions & 3 deletions android/app/src/main/res/layout-land/fragment_logger.xml
Original file line number Diff line number Diff line change
Expand Up @@ -156,15 +156,25 @@
app:layout_constraintStart_toEndOf="@+id/ipAddress"
app:layout_constraintTop_toTopOf="parent" />


<CheckBox
android:id="@+id/videoCaptureCheckBox"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checked="true"
android:text="Capture Video"
app:layout_constraintStart_toStartOf="@id/previewCheckBox"
app:layout_constraintTop_toBottomOf="@id/previewCheckBox" />

<CheckBox
android:id="@+id/trainingDataCheckBox"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checked="true"
android:text="Training Images"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="@id/previewCheckBox"
app:layout_constraintTop_toBottomOf="@+id/previewCheckBox" />
app:layout_constraintStart_toStartOf="@id/videoCaptureCheckBox"
app:layout_constraintTop_toBottomOf="@+id/videoCaptureCheckBox" />


<TextView
android:id="@+id/server"
Expand Down
14 changes: 12 additions & 2 deletions android/app/src/main/res/layout/fragment_logger.xml
Original file line number Diff line number Diff line change
Expand Up @@ -172,14 +172,24 @@
app:layout_constraintStart_toEndOf="@+id/ipAddress"
app:layout_constraintTop_toTopOf="parent" />

<CheckBox
android:id="@+id/videoCaptureCheckBox"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checked="true"
android:text="Capture Video"
app:layout_constraintStart_toStartOf="@id/previewCheckBox"
app:layout_constraintTop_toBottomOf="@id/previewCheckBox" />

<CheckBox
android:id="@+id/trainingDataCheckBox"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checked="true"
android:text="Training Images"
app:layout_constraintStart_toStartOf="@id/previewCheckBox"
app:layout_constraintTop_toBottomOf="@+id/previewCheckBox" />
app:layout_constraintStart_toStartOf="@id/videoCaptureCheckBox"
app:layout_constraintTop_toBottomOf="@+id/videoCaptureCheckBox" />


<TextView
android:id="@+id/server"
Expand Down
2 changes: 1 addition & 1 deletion android/controller/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ dependencies {
implementation 'org.videolan.android:libvlc-all:3.3.14'

// WebRTC
implementation 'org.webrtc:google-webrtc:1.0.+'
implementation 'org.webrtc:google-webrtc:1.0.32006'

// For a library module, uncomment the following line and comment the one after
// apply plugin: 'com.android.library'
Expand Down