Skip to content

Commit 39a47a6

Browse files
committed
first version of dvr implementation. work in progress
1 parent d30109a commit 39a47a6

File tree

8 files changed

+229
-139
lines changed

8 files changed

+229
-139
lines changed

app/src/main/java/com/fpvout/digiview/MainActivity.java

+55-9
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.fpvout.digiview;
22

3+
import android.Manifest;
34
import android.animation.Animator;
45
import android.animation.AnimatorListenerAdapter;
56
import android.animation.LayoutTransition;
@@ -8,8 +9,10 @@
89
import android.content.Intent;
910
import android.content.IntentFilter;
1011
import android.content.SharedPreferences;
12+
import android.content.pm.PackageManager;
1113
import android.hardware.usb.UsbDevice;
1214
import android.hardware.usb.UsbManager;
15+
import android.os.Build;
1316
import android.os.Bundle;
1417
import android.preference.PreferenceManager;
1518
import android.util.Log;
@@ -20,9 +23,12 @@
2023
import android.view.View;
2124
import android.view.ViewGroup;
2225
import android.view.WindowManager;
26+
import android.widget.Toast;
2327

28+
import androidx.annotation.NonNull;
2429
import androidx.appcompat.app.ActionBar;
2530
import androidx.appcompat.app.AppCompatActivity;
31+
import androidx.core.app.ActivityCompat;
2632
import io.sentry.SentryLevel;
2733
import io.sentry.android.core.SentryAndroid;
2834

@@ -78,15 +84,16 @@ protected void onCreate(Bundle savedInstanceState) {
7884
actionBar.hide();
7985
}
8086

81-
findViewById(R.id.recordbt).setOnClickListener(view -> {
87+
recordButton = findViewById(R.id.recordbt);
88+
recordButton.setOnClickListener(view -> {
8289
if (recorder != null) {
8390
if (recorder.isRecording()) {
8491
recorder.stop();
8592
} else {
8693
recorder.start();
8794
}
8895
} else {
89-
96+
Toast.makeText(this, this.getText(R.string.no_dvr_video), Toast.LENGTH_LONG).show();
9097
}
9198
});
9299

@@ -115,7 +122,6 @@ public void onClick(View v) {
115122
v.getContext().startActivity(intent);
116123
}
117124
});
118-
recordButton = findViewById(R.id.recordbt);
119125

120126
sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
121127

@@ -355,6 +361,20 @@ public void onResume() {
355361
actionBar.hide();
356362
}
357363

364+
365+
settingsButton.setAlpha(1);
366+
recordButton.setAlpha(1);
367+
autoHideSettingsButton();
368+
updateWatermark();
369+
updateVideoZoom();
370+
371+
if(checkStoragePermission()){
372+
// permission already granted
373+
finishStartup();
374+
}
375+
}
376+
377+
private void finishStartup(){
358378
if (!usbConnected) {
359379
if (searchDevice()) {
360380
Log.d(TAG, "APP - On Resume usbDevice device found");
@@ -363,12 +383,39 @@ public void onResume() {
363383
overlayView.showOpaque(R.string.waiting_for_usb_device, OverlayStatus.Disconnected);
364384
}
365385
}
386+
}
366387

367-
settingsButton.setAlpha(1);
368-
recordButton.setAlpha(1);
369-
autoHideSettingsButton();
370-
updateWatermark();
371-
updateVideoZoom();
388+
private boolean checkStoragePermission() {
389+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
390+
if (checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE)
391+
== PackageManager.PERMISSION_GRANTED &&
392+
checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE)
393+
== PackageManager.PERMISSION_GRANTED &&
394+
checkSelfPermission(Manifest.permission.RECORD_AUDIO)
395+
== PackageManager.PERMISSION_GRANTED) {
396+
return true;
397+
398+
}else{
399+
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.RECORD_AUDIO, Manifest.permission.CAMERA }, 1);
400+
return false;
401+
}
402+
}
403+
return true;
404+
}
405+
406+
@Override
407+
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
408+
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
409+
410+
if(requestCode == 1){
411+
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
412+
413+
finishStartup();
414+
}
415+
else {
416+
overlayView.showOpaque("Storage access is required.", OverlayStatus.Error);
417+
}
418+
}
372419
}
373420

374421
@Override
@@ -438,5 +485,4 @@ private void checkDataCollectionAgreement() {
438485
}
439486

440487
}
441-
442488
}
Original file line numberDiff line numberDiff line change
@@ -1,62 +1,43 @@
11
package com.fpvout.digiview.dvr;
22

3-
import android.Manifest;
43
import android.app.Activity;
54
import android.media.MediaRecorder;
65
import android.os.Environment;
7-
import android.os.Looper;
86
import android.util.Log;
97
import android.widget.ImageButton;
108
import android.widget.Toast;
119

12-
import com.fpvout.digiview.InputStreamDataSource;
1310
import com.fpvout.digiview.R;
1411
import com.fpvout.digiview.VideoReaderExoplayer;
15-
import com.fpvout.digiview.helpers.Mp4Muxer;
16-
import com.fpvout.digiview.helpers.ThreadPerTaskExecutor;
17-
18-
import org.mp4parser.Container;
19-
import org.mp4parser.muxer.DataSource;
20-
import org.mp4parser.muxer.FileDataSourceImpl;
21-
import org.mp4parser.muxer.Movie;
22-
import org.mp4parser.muxer.builder.DefaultMp4Builder;
23-
import org.mp4parser.muxer.tracks.AACTrackImpl;
24-
import org.mp4parser.muxer.tracks.h264.H264TrackImpl;
25-
26-
import java.io.ByteArrayOutputStream;
12+
import com.fpvout.digiview.helpers.StreamDumper;
13+
2714
import java.io.File;
28-
import java.io.FileNotFoundException;
29-
import java.io.FileOutputStream;
3015
import java.io.IOException;
31-
import java.io.OutputStream;
32-
import java.util.Date;
33-
34-
import androidx.core.app.ActivityCompat;
35-
import usb.AndroidUSBOutputStream;
16+
import java.text.SimpleDateFormat;
17+
import java.util.Calendar;
3618

3719
public class DVR {
3820
private static final int WRITE_EXTERNAL_STORAGE = 0;
39-
private final Activity _activity;
40-
private boolean _recordAmbientAudio;
41-
private MediaRecorder _recorder;
21+
private final Activity activity;
22+
private boolean recordAmbientAudio;
23+
private MediaRecorder recorder;
4224
private boolean recording = false;
4325
private static DVR instance;
4426
private static final String DVR_LOG_TAG = "DVR";
4527
private String defaultFolder = "";
46-
private String _ambietAudio;
47-
private String _videoFile;
48-
private String _dvrFile;
49-
private VideoReaderExoplayer _mPlayer;
28+
private String ambietAudio;
29+
private String videoFile;
30+
private String dvrFile;
31+
private VideoReaderExoplayer mPlayer;
5032
private File dvrTmpFile;
5133
private String fileName;
52-
private AndroidUSBOutputStream dvrOutputStream;
34+
private StreamDumper streamDumper;
5335

5436
DVR(Activity activity, boolean recordAmbientAudio){
55-
_activity = activity;
56-
_recordAmbientAudio = recordAmbientAudio;
57-
defaultFolder = Environment.getExternalStorageDirectory().getAbsolutePath()+ "/" +_activity.getApplicationInfo().loadLabel(_activity.getPackageManager()).toString();
58-
ActivityCompat.requestPermissions(_activity, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.RECORD_AUDIO, Manifest.permission.CAMERA }, WRITE_EXTERNAL_STORAGE);
59-
37+
this.activity = activity;
38+
this.recordAmbientAudio = recordAmbientAudio;
39+
defaultFolder = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES) + "/" + this.activity.getApplicationInfo().loadLabel(this.activity.getPackageManager()).toString();
40+
streamDumper = new StreamDumper(activity, defaultFolder);
6041
}
6142

6243
public static DVR getInstance(Activity context, boolean recordAmbientAudio){
@@ -67,60 +48,55 @@ public static DVR getInstance(Activity context, boolean recordAmbientAudio){
6748
}
6849

6950
public void init(VideoReaderExoplayer mPlayer) throws IOException {
70-
this._mPlayer = mPlayer;
51+
this.mPlayer = mPlayer;
7152

72-
_recorder = new MediaRecorder();
73-
_recorder.setAudioSource(MediaRecorder.AudioSource.MIC);
74-
_recorder.setOutputFormat(MediaRecorder.OutputFormat.AAC_ADTS);
75-
_recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
53+
recorder = new MediaRecorder();
54+
recorder.setAudioSource(MediaRecorder.AudioSource.MIC);
55+
recorder.setOutputFormat(MediaRecorder.OutputFormat.AAC_ADTS);
56+
recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
7657
}
7758

7859
public void recordVideoDVR(byte[] buffer, int offset, int readLength) {
7960
if (isRecording()) {
80-
try {
81-
if (dvrTmpFile != null) {
82-
dvrOutputStream.write(buffer, offset, readLength);
83-
}
84-
} catch (Exception e) {
85-
e.printStackTrace();
86-
}
61+
streamDumper.dump( buffer, offset, readLength);
8762
}
8863
}
8964

9065
public void start() {
91-
if ( _mPlayer.isStreaming()) {
66+
if ( mPlayer.isStreaming()) {
9267
this.recording = true;
93-
fileName = String.valueOf(new Date().getTime());
94-
_ambietAudio = defaultFolder + "/tmp_" + fileName + ".aac";
95-
_videoFile = defaultFolder + "/tmp_" + fileName + ".h264";
96-
_dvrFile = defaultFolder + "/DVR_" + fileName + ".mp4";
68+
fileName = new SimpleDateFormat("yyyy-MM-dd HH-mm-ss")
69+
.format(Calendar.getInstance().getTime());
70+
ambietAudio = "/DigiView_" + fileName + ".aac";
71+
videoFile ="/DigiView_"+fileName+".h264";
72+
dvrFile = "/DigiView_" + fileName + ".mp4";
73+
74+
Log.d(DVR_LOG_TAG, "creating folder for dvr saving ...");
75+
File objFolder = new File(defaultFolder);
76+
if (!objFolder.exists())
77+
objFolder.mkdir();
78+
9779

9880
Log.d(DVR_LOG_TAG, "start recording ...");
99-
Toast.makeText(_activity, _activity.getText(R.string.recording_started), Toast.LENGTH_LONG).show();
100-
((ImageButton)_activity.findViewById(R.id.recordbt)).setImageResource(R.drawable.stop);
101-
102-
ThreadPerTaskExecutor threadPerTaskExecutor = new ThreadPerTaskExecutor();
103-
threadPerTaskExecutor.execute(() -> {
104-
Log.d(DVR_LOG_TAG, "creating folder for dvr saving ...");
105-
File objFolder = new File(defaultFolder);
106-
if(!objFolder.exists()){
107-
objFolder.mkdir();
108-
}
81+
streamDumper.init(videoFile, ambietAudio, dvrFile);
10982

110-
dvrTmpFile = new File(_videoFile);
111-
if (_recordAmbientAudio) {
112-
Log.d(DVR_LOG_TAG, "starting abient recording ...");
113-
_recorder.setOutputFile(_ambietAudio);
114-
try {
115-
_recorder.prepare();
116-
_recorder.start(); // Ambient Audio Recording is now started
117-
} catch (IOException e) {
118-
e.printStackTrace();
119-
}
83+
Toast.makeText(activity, activity.getText(R.string.recording_started), Toast.LENGTH_LONG).show();
84+
((ImageButton) activity.findViewById(R.id.recordbt)).setImageResource(R.drawable.stop);
85+
86+
87+
88+
if (recordAmbientAudio) {
89+
Log.d(DVR_LOG_TAG, "starting ambient recording ...");
90+
recorder.setOutputFile(defaultFolder + ambietAudio);
91+
try {
92+
recorder.prepare();
93+
recorder.start(); // Ambient Audio Recording is now started
94+
} catch (IOException e) {
95+
e.printStackTrace();
12096
}
121-
});
97+
}
12298
} else {
123-
Toast.makeText(_activity, "Stream not ready", Toast.LENGTH_LONG).show();
99+
Toast.makeText(activity, "Stream not ready", Toast.LENGTH_LONG).show();
124100
}
125101
}
126102

@@ -130,19 +106,18 @@ public boolean isRecording(){
130106

131107
public void stop() {
132108
Log.d(DVR_LOG_TAG, "stop recording ...");
133-
Toast.makeText(_activity, _activity.getText(R.string.recording_stopped), Toast.LENGTH_LONG).show();
134-
((ImageButton)_activity.findViewById(R.id.recordbt)).setImageResource(R.drawable.record);
135-
136-
if (_recordAmbientAudio) {
137-
_recorder.stop();
109+
Toast.makeText(activity, activity.getText(R.string.recording_stopped), Toast.LENGTH_LONG).show();
110+
((ImageButton) activity.findViewById(R.id.recordbt)).setImageResource(R.drawable.record);
138111

139-
Toast.makeText(_activity, _activity.getString(R.string.dvr_merge_audio_video), Toast.LENGTH_LONG).show();
140-
Mp4Muxer muxer = new Mp4Muxer(new File(_videoFile), _ambietAudio, _dvrFile);
141-
muxer.start();
142-
} else {
143-
new File(_videoFile).renameTo( new File(_dvrFile)); // No Ambient recording just dvr
112+
if (recordAmbientAudio) {
113+
recorder.stop();
114+
try {
115+
init(mPlayer);
116+
} catch (IOException e) {
117+
e.printStackTrace();
118+
}
144119
}
145-
120+
streamDumper.stop();
146121
this.recording = false;
147122
}
148123
}

0 commit comments

Comments
 (0)