package com.example.greenwatch; | package com.example.greenwatch; | ||||
import android.graphics.SurfaceTexture; | |||||
import android.media.MediaCodec; | import android.media.MediaCodec; | ||||
import android.media.MediaExtractor; | import android.media.MediaExtractor; | ||||
import android.media.MediaFormat; | import android.media.MediaFormat; | ||||
import android.media.MediaMuxer; | import android.media.MediaMuxer; | ||||
import android.media.MediaRecorder; | import android.media.MediaRecorder; | ||||
import android.os.Environment; | import android.os.Environment; | ||||
import android.view.Surface; | |||||
import android.view.SurfaceHolder; | import android.view.SurfaceHolder; | ||||
import java.io.File; | import java.io.File; | ||||
private Runnable videoRecorderRunnable; | private Runnable videoRecorderRunnable; | ||||
private MediaRecorder videoRecorder; | private MediaRecorder videoRecorder; | ||||
private MediaRecorder audioRecorder; | private MediaRecorder audioRecorder; | ||||
private SurfaceHolder previewHolder; | |||||
//private SurfaceHolder previewHolder; | |||||
private Surface surface; | |||||
private Thread videoThread; // Video-Thread als Instanzvariable | private Thread videoThread; // Video-Thread als Instanzvariable | ||||
private Thread audioThread; // Audio-Thread als Instanzvariable | private Thread audioThread; // Audio-Thread als Instanzvariable | ||||
public AlarmRecorder(SurfaceHolder previewHolder) { | |||||
public AlarmRecorder(SurfaceTexture surfaceTexture) { | |||||
audioRecorder = new MediaRecorder(); | audioRecorder = new MediaRecorder(); | ||||
videoRecorder = new MediaRecorder(); | videoRecorder = new MediaRecorder(); | ||||
videoExtractor = new MediaExtractor(); | videoExtractor = new MediaExtractor(); | ||||
audioExtractor = new MediaExtractor(); | audioExtractor = new MediaExtractor(); | ||||
this.previewHolder = previewHolder; | |||||
this.surface = new Surface(surfaceTexture); | |||||
} | } | ||||
public void startRecording() { | public void startRecording() { | ||||
createStoragePaths(); //Speicherort und -namen für Audio- und Video-Datei | createStoragePaths(); //Speicherort und -namen für Audio- und Video-Datei | ||||
audioRecorderRunnable = new AudioRecorder(audioRecorder, audioPath); | audioRecorderRunnable = new AudioRecorder(audioRecorder, audioPath); | ||||
videoRecorderRunnable = new VideoRecorder(videoRecorder, videoPath, previewHolder); | |||||
videoRecorderRunnable = new VideoRecorder(videoRecorder, videoPath, surface); | |||||
audioThread = new Thread(audioRecorderRunnable); | audioThread = new Thread(audioRecorderRunnable); | ||||
videoThread = new Thread(videoRecorderRunnable); | videoThread = new Thread(videoRecorderRunnable); | ||||
if (videoFile.exists() && audioFile.exists()) { | if (videoFile.exists() && audioFile.exists()) { | ||||
//Wenn Video- und Audioaufzeichnung gestoppt und abgespeichert sind, beginne mit dem Mergeprozess der beiden | //Wenn Video- und Audioaufzeichnung gestoppt und abgespeichert sind, beginne mit dem Mergeprozess der beiden | ||||
mergeVideoWithAudio(); | mergeVideoWithAudio(); | ||||
} else { } | |||||
} | |||||
} catch (RuntimeException stopException) { | } catch (RuntimeException stopException) { | ||||
stopException.printStackTrace(); | stopException.printStackTrace(); | ||||
} | } |
import android.Manifest; | import android.Manifest; | ||||
import android.content.pm.PackageManager; | import android.content.pm.PackageManager; | ||||
import android.graphics.SurfaceTexture; | |||||
import android.os.Bundle; | import android.os.Bundle; | ||||
import android.view.SurfaceView; | |||||
import android.view.TextureView; | |||||
import android.view.View; | import android.view.View; | ||||
import android.widget.Button; | import android.widget.Button; | ||||
import android.widget.Toast; | import android.widget.Toast; | ||||
import androidx.core.app.ActivityCompat; | import androidx.core.app.ActivityCompat; | ||||
import androidx.core.content.ContextCompat; | import androidx.core.content.ContextCompat; | ||||
public class MainActivity extends AppCompatActivity { | |||||
public class MainActivity extends AppCompatActivity implements TextureView.SurfaceTextureListener{ | |||||
private boolean isRecording = false; | private boolean isRecording = false; | ||||
private static final int REQUEST_PERMISSION = 200; | private static final int REQUEST_PERMISSION = 200; | ||||
private Button button; | private Button button; | ||||
private SurfaceView surfaceView; | |||||
private TextureView textureView; | |||||
private AlarmRecorder alarmRecorder; | private AlarmRecorder alarmRecorder; | ||||
private static final int REQUEST_PERMISSIONS = 123; | |||||
@Override | @Override | ||||
protected void onCreate(Bundle savedInstanceState) { | protected void onCreate(Bundle savedInstanceState) { | ||||
setContentView(R.layout.activity_main); | setContentView(R.layout.activity_main); | ||||
button = findViewById(R.id.button); | button = findViewById(R.id.button); | ||||
surfaceView = findViewById(R.id.surfaceView); | |||||
alarmRecorder = new AlarmRecorder(surfaceView.getHolder()); | |||||
textureView = findViewById(R.id.textureView); | |||||
textureView.setSurfaceTextureListener(this); | |||||
button.setOnClickListener(new View.OnClickListener() { | button.setOnClickListener(new View.OnClickListener() { | ||||
@Override | @Override | ||||
}); | }); | ||||
} | } | ||||
@Override | |||||
public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture, int width, int height) { | |||||
alarmRecorder = new AlarmRecorder(surfaceTexture); | |||||
} | |||||
@Override | |||||
public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) { | |||||
// Die Größe der SurfaceTexture hat sich geändert | |||||
// Hier können entsprechende Anpassungen vorgenommen werden | |||||
} | |||||
@Override | |||||
public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) { | |||||
// SurfaceTexture wurde zerstört | |||||
// Hier können entsprechende Bereinigungen durchgeführt werden | |||||
return true; | |||||
} | |||||
@Override | |||||
public void onSurfaceTextureUpdated(SurfaceTexture surface) { | |||||
// SurfaceTexture wurde aktualisiert | |||||
// Hier können entsprechende Aktionen ausgeführt werden, wenn gewünscht | |||||
} | |||||
private SurfaceTexture getSurfaceTexture() { | |||||
return textureView.getSurfaceTexture(); | |||||
} | |||||
@Override | @Override | ||||
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { | public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { | ||||
super.onRequestPermissionsResult(requestCode, permissions, grantResults); | super.onRequestPermissionsResult(requestCode, permissions, grantResults); |
package com.example.greenwatch; | package com.example.greenwatch; | ||||
import android.media.MediaRecorder; | import android.media.MediaRecorder; | ||||
import android.view.Surface; | |||||
import android.view.SurfaceHolder; | import android.view.SurfaceHolder; | ||||
import java.io.IOException; | import java.io.IOException; | ||||
public class VideoRecorder implements Runnable{ | public class VideoRecorder implements Runnable{ | ||||
private final MediaRecorder videoRecorder; | private final MediaRecorder videoRecorder; | ||||
private final String videoPath; | private final String videoPath; | ||||
private SurfaceHolder previewHolder; | |||||
//private SurfaceHolder previewHolder; | |||||
private Surface surface; | |||||
public VideoRecorder(MediaRecorder videoRecorder, String videoPath, SurfaceHolder previewHolder) { | |||||
public VideoRecorder(MediaRecorder videoRecorder, String videoPath, Surface surface) { | |||||
this.videoRecorder = videoRecorder; | this.videoRecorder = videoRecorder; | ||||
this.videoPath = videoPath; | this.videoPath = videoPath; | ||||
this.previewHolder = previewHolder; | |||||
this.surface = surface; | |||||
} | } | ||||
@Override | @Override | ||||
public void run() { | public void run() { | ||||
videoRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.DEFAULT); | videoRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.DEFAULT); | ||||
videoRecorder.setOutputFile(videoPath); | videoRecorder.setOutputFile(videoPath); | ||||
videoRecorder.setOrientationHint(90); | videoRecorder.setOrientationHint(90); | ||||
videoRecorder.setPreviewDisplay(previewHolder.getSurface()); | |||||
videoRecorder.setPreviewDisplay(surface); | |||||
try { | try { | ||||
videoRecorder.prepare(); | videoRecorder.prepare(); |
android:layout_height="match_parent" | android:layout_height="match_parent" | ||||
tools:context=".MainActivity"> | tools:context=".MainActivity"> | ||||
<SurfaceView | |||||
android:id="@+id/surfaceView" | |||||
android:layout_width="1dp" | |||||
android:layout_height="1dp" | |||||
<TextureView | |||||
android:id="@+id/textureView" | |||||
android:layout_width="1sp" | |||||
android:layout_height="1sp" | |||||
android:visibility="visible" | android:visibility="visible" | ||||
app:layout_constraintBottom_toBottomOf="parent" | app:layout_constraintBottom_toBottomOf="parent" | ||||
app:layout_constraintEnd_toEndOf="parent" | app:layout_constraintEnd_toEndOf="parent" | ||||
app:layout_constraintHorizontal_bias="1.0" | app:layout_constraintHorizontal_bias="1.0" | ||||
app:layout_constraintStart_toStartOf="parent" | app:layout_constraintStart_toStartOf="parent" | ||||
app:layout_constraintTop_toTopOf="parent" | |||||
app:layout_constraintTop_toBottomOf="@id/button" | |||||
app:layout_constraintVertical_bias="0.0" /> | app:layout_constraintVertical_bias="0.0" /> | ||||
<Button | <Button |