Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- package com.chronotum.testing2;
- import android.Manifest;
- import android.annotation.SuppressLint;
- import android.content.Context;
- import android.content.SharedPreferences;
- import android.content.pm.PackageManager;
- import android.graphics.ImageFormat;
- import android.hardware.camera2.CameraAccessException;
- import android.hardware.camera2.CameraCaptureSession;
- import android.hardware.camera2.CameraCharacteristics;
- import android.hardware.camera2.CameraDevice;
- import android.hardware.camera2.CameraManager;
- import android.hardware.camera2.CameraMetadata;
- import android.hardware.camera2.CaptureRequest;
- import android.hardware.camera2.params.StreamConfigurationMap;
- import android.media.MediaRecorder;
- import android.os.Build;
- import android.os.Bundle;
- import android.os.Environment;
- import android.os.Handler;
- import android.os.HandlerThread;
- import android.os.VibrationEffect;
- import android.os.Vibrator;
- import android.util.Log;
- import android.util.Size;
- import android.view.Menu;
- import android.view.MenuItem;
- import android.view.Surface;
- import android.view.View;
- import android.widget.Toast;
- import androidx.annotation.NonNull;
- import androidx.appcompat.app.AppCompatActivity;
- import androidx.appcompat.widget.Toolbar;
- import com.google.android.material.floatingactionbutton.FloatingActionButton;
- import java.io.File;
- import java.io.IOException;
- import java.text.SimpleDateFormat;
- import java.util.ArrayList;
- import java.util.Collections;
- import java.util.Date;
- import java.util.concurrent.Semaphore;
- import java.util.concurrent.TimeUnit;
- import static android.os.Environment.getExternalStoragePublicDirectory;
- public class MainActivity extends AppCompatActivity {
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- Toolbar toolbar = findViewById(R.id.toolbar);
- setSupportActionBar(toolbar);
- Log.v(TAG, "EXTERNAL STORAGE AVAILABLE:"+Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState()));
- cameraManager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
- vibrator = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
- checkAllRequiredPermissions();
- FloatingActionButton fab = findViewById(R.id.fab);
- fab.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- startRecording();
- }
- });
- }
- private boolean checkAllRequiredPermissions() {
- //Missing permissions
- ArrayList<String> requiredPermissions = new ArrayList<>();
- //Fundamental permissions
- if (checkCallingOrSelfPermission(Manifest.permission.CAMERA) == PackageManager.PERMISSION_DENIED) {
- requiredPermissions.add(Manifest.permission.CAMERA);
- }
- if (checkCallingOrSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_DENIED) {
- requiredPermissions.add(Manifest.permission.WRITE_EXTERNAL_STORAGE);
- }
- Log.e(TAG, "TEST Manifest.permission.READ_EXTERNAL_STORAGE");
- if (checkCallingOrSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_DENIED) {
- requiredPermissions.add(Manifest.permission.READ_EXTERNAL_STORAGE);
- Log.e(TAG, "TEST Manifest.permission.READ_EXTERNAL_STORAGE");
- }
- //Audio
- if ((checkCallingOrSelfPermission(Manifest.permission.RECORD_AUDIO) == PackageManager.PERMISSION_DENIED)) {
- requiredPermissions.add(Manifest.permission.RECORD_AUDIO);
- }
- //Request required permissions
- if (!requiredPermissions.isEmpty()) {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
- requestPermissions(requiredPermissions.toArray(new String[0]), 0);
- //Toast.makeText(getBaseContext(),"Error: Permission requirements are not met!",Toast.LENGTH_LONG).show();
- }
- return false;
- }
- return true;
- }
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
- // Inflate the menu; this adds items to the action bar if it is present.
- getMenuInflater().inflate(R.menu.menu_main, menu);
- return true;
- }
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- // Handle action bar item clicks here. The action bar will
- // automatically handle clicks on the Home/Up button, so long
- // as you specify a parent activity in AndroidManifest.xml.
- int id = item.getItemId();
- //noinspection SimplifiableIfStatement
- if (id == R.id.action_settings) {
- return true;
- }
- return super.onOptionsItemSelected(item);
- }
- //TAG
- private String TAG = "Service";
- //Managers
- private static CameraManager cameraManager;
- private static Vibrator vibrator;
- //States
- public static boolean isRecording = false;
- public static boolean isSettingUpRecording = false;
- //Preference variables
- private static int cameraId;
- private static Integer cameraDirection;
- private static Size cameraResolution;
- private static int cameraOrientation;
- private static boolean flashlightEnable;
- private static boolean durationEnabled;
- private static int recordingDuration;
- private static boolean repeatingEnabled;
- private static int recordingRepeat;
- private static long recordingFileSize;
- private static File recordingDirectory;
- private static boolean vibrationStartRecordingEnabled;
- private static boolean vibrationStartOfEachFileEnabled;
- private static boolean vibrationStopRecordingEnabled;
- private static boolean microphoneEnabled;
- //Thread
- private HandlerThread mBackgroundThread;
- private Handler mBackgroundHandler;
- //Recording
- private static MediaRecorder mMediaRecorder;
- private static CameraCaptureSession captureSession;
- private static CaptureRequest.Builder captureRequestBuilder;
- //Camera lock
- private Semaphore mCameraOpenCloseLock = new Semaphore(1);
- /**
- * A reference to the opened {@link android.hardware.camera2.CameraDevice}.
- */
- private CameraDevice mCameraDevice;
- public void startRecording() {
- //Check if the we are already setting up settings or if we are already recording
- if (isRecording || isSettingUpRecording) {
- Log.v(TAG, "Start recording denied \n" +
- "isRecording: " + isRecording + "\n" +
- "isSettingUpRecording: " + isSettingUpRecording + "\n" +
- "\n" +
- "Start recording denied");
- return;
- }
- //We are now setting up the recording session
- isSettingUpRecording = true;
- //Setup preferences
- if (!setupPreferences()) {
- stopRecording();
- }
- startBackgroundThread();
- if (!openCamera()) {
- Toast.makeText(getBaseContext(), "ERROR OPENING CAMERA", Toast.LENGTH_LONG).show();
- stopRecording();
- }
- }
- /**
- * Tries to open a {@link CameraDevice}. The result is listened by `mStateCallback`.
- */
- private boolean openCamera() {
- if (checkCallingOrSelfPermission(Manifest.permission.CAMERA) == PackageManager.PERMISSION_DENIED) {
- return false;
- }
- try {
- if (!mCameraOpenCloseLock.tryAcquire(2500, TimeUnit.MILLISECONDS)) {
- Log.e(TAG, "Time out waiting to lock camera opening.");
- return false;
- }
- cameraManager.openCamera(String.valueOf(cameraId), new CameraDevice.StateCallback() {
- @Override
- public void onOpened(@NonNull CameraDevice camera) {
- Log.i(TAG, "onOpened");
- mCameraDevice = camera;
- //Select method by version
- if (21 <= Build.VERSION.SDK_INT && Build.VERSION.SDK_INT < 26) {
- Log.i(TAG, "VERSION 21");
- // setupV21();
- // startRecordingSessionV21();
- } else if (26 <= Build.VERSION.SDK_INT) {
- Log.i(TAG, "VERSION 26");
- startRecordingSessionV26();
- }
- mCameraOpenCloseLock.release();
- }
- @Override
- public void onDisconnected(@NonNull CameraDevice camera) {
- Log.i(TAG, "onDisconnected");
- mCameraOpenCloseLock.release();
- camera.close();
- mCameraDevice = null;
- }
- @Override
- public void onError(@NonNull CameraDevice camera, int error) {
- Log.e(TAG, "onError");
- mCameraOpenCloseLock.release();
- camera.close();
- mCameraDevice = null;
- }
- }, null);
- } catch (InterruptedException | CameraAccessException e) {
- e.printStackTrace();
- return false;
- }
- return true;
- }
- public void stopRecording(){
- }
- public boolean setupPreferences() {
- //Id of selected camera
- cameraId = 0;
- try {
- //Camera properties
- CameraCharacteristics cameraCharacteristics = cameraManager.getCameraCharacteristics(Integer.toString(cameraId));
- //Direction of the camera
- cameraDirection = cameraCharacteristics.get(CameraCharacteristics.LENS_FACING);
- //Camera resolution
- int cameraResolutionIndex = 0;
- cameraResolution = cameraCharacteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP).getOutputSizes(MediaRecorder.class)[cameraResolutionIndex];
- StreamConfigurationMap streamConfigurationMap =cameraCharacteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
- //Orientation
- cameraOrientation = 0;
- //Camera Extra
- flashlightEnable = true;
- //Audio
- microphoneEnabled = true;
- //Duration
- durationEnabled = true;
- recordingDuration = 3600 * 1000;
- //Repeating
- repeatingEnabled = true;
- recordingRepeat = 12;
- //Max value if set to 0
- if (recordingRepeat == 0) {
- recordingRepeat = Integer.MAX_VALUE - 1;
- }
- recordingFileSize = 35 * 1024 * 1024;
- recordingDirectory = new File(Environment.getExternalStorageDirectory(), Environment.DIRECTORY_DCIM + "/Camera");
- recordingDirectory.mkdirs();
- Log.v(TAG, "CREATE FOLDER: CHECK");
- if (!recordingDirectory.exists()) {
- }
- Log.v(TAG, "FOLDER EXISTS: "+recordingDirectory.exists());
- // Log.v(TAG, "CREATE FOLDER: "+recordingDirectory.mkdirs());
- //Vibration
- vibrationStartRecordingEnabled = true;
- vibrationStartOfEachFileEnabled = true;
- vibrationStopRecordingEnabled = true;
- } catch (CameraAccessException e) {
- e.printStackTrace();
- return false;
- }
- return true;
- }
- //Message threads
- /**
- * Starts a background thread and its {@link Handler}.
- */
- private void startBackgroundThread() {
- mBackgroundThread = new HandlerThread("CameraBackground");
- mBackgroundThread.start();
- mBackgroundHandler = new Handler(mBackgroundThread.getLooper());
- }
- /**
- * Stops the background thread and its {@link Handler}.
- */
- private void stopBackgroundThread() {
- mBackgroundThread.quitSafely();
- try {
- mBackgroundThread.join();
- mBackgroundThread = null;
- mBackgroundHandler = null;
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- //SDK version 26 (sdk version 26 and above)
- private void startRecordingSessionV26() {
- prepareMediaRecorderV26();
- try {
- captureRequestBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_RECORD);
- } catch (CameraAccessException e) {
- e.printStackTrace();
- stopRecording();
- }
- Surface recorderSurface = mMediaRecorder.getSurface();
- captureRequestBuilder.addTarget(recorderSurface);
- if (flashlightEnable)
- captureRequestBuilder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_TORCH);
- captureRequestBuilder.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO);
- //Start recording on configured
- try {
- mCameraDevice.createCaptureSession(Collections.singletonList(recorderSurface), new CameraCaptureSession.StateCallback() {
- @Override
- public void onConfigured(@NonNull CameraCaptureSession cameraCaptureSession) {
- Log.i(TAG, "onConfigured");
- try {
- captureSession = cameraCaptureSession;
- captureSession.setRepeatingRequest(captureRequestBuilder.build(), null, mBackgroundHandler);
- //Start recording
- mMediaRecorder.start();
- //Update states
- isRecording = true;
- //Update UI
- // callbacks.recordingStarted();
- } catch (IllegalStateException | CameraAccessException e) {
- e.printStackTrace();
- stopRecording();
- }
- isSettingUpRecording = false;
- }
- @Override
- public void onConfigureFailed(@NonNull CameraCaptureSession cameraCaptureSession) {
- Log.e(TAG, "onConfigureFailed");
- stopRecording();
- }
- }, mBackgroundHandler);
- } catch (IllegalStateException | CameraAccessException e) {
- e.printStackTrace();
- }
- }
- private File presetRecordingFile(File directory, int clipNumber, String timeStamp) {
- return new File(directory.getPath() + File.separator + "file_" + timeStamp + "_" + clipNumber + ".mp4");
- }
- private void prepareMediaRecorderV26() {
- mMediaRecorder = new MediaRecorder();
- mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER);
- mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);
- mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
- mMediaRecorder.setVideoEncodingBitRate(10000000);
- mMediaRecorder.setVideoFrameRate(30);
- mMediaRecorder.setVideoSize(cameraResolution.getWidth(), cameraResolution.getHeight());
- Log.i(TAG, "Width:"+ cameraResolution.getWidth()+" Height:"+ cameraResolution.getHeight());
- mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
- mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
- // Save location and file
- @SuppressLint("SimpleDateFormat")
- final String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
- final File outputFile = presetRecordingFile(recordingDirectory, 1, timeStamp);
- mMediaRecorder.setOutputFile(outputFile.getAbsolutePath());
- mMediaRecorder.setMaxFileSize(recordingFileSize);
- mMediaRecorder.setMaxDuration(120000);
- mMediaRecorder.setOrientationHint(cameraOrientation);
- //Todo: native max duration leads to MediaServer dying
- //mMediaRecorder.setMaxDuration(recordingDuration);
- //mMediaRecorder.setMaxFileSize(recordingFileSize);
- //Listen to file size and other relevant info to continue recording
- mMediaRecorder.setOnInfoListener(new MediaRecorder.OnInfoListener() {
- int i = 2;
- String startTimeStamp = timeStamp;
- File currentOutputFile = outputFile;
- private String TAG = "MediaRecorder info listener";
- @SuppressLint("NewApi")
- @Override
- public void onInfo(MediaRecorder mr, int what, int extra) {
- switch (what) {
- case MediaRecorder.MEDIA_RECORDER_INFO_MAX_FILESIZE_APPROACHING:
- try {
- currentOutputFile = presetRecordingFile(recordingDirectory, i, startTimeStamp);
- mr.setNextOutputFile(currentOutputFile);
- i++;
- } catch (IOException e) {
- e.printStackTrace();
- }
- Log.i(TAG, "Max file size approaching");
- break;
- case MediaRecorder.MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED:
- Log.i(TAG, "Max file size reached");
- stopRecording();
- break;
- case MediaRecorder.MEDIA_RECORDER_INFO_NEXT_OUTPUT_FILE_STARTED:
- Log.i(TAG, "OutputFile: " + currentOutputFile);
- if (vibrationStartRecordingEnabled && vibrationStartOfEachFileEnabled) {
- vibrator.vibrate(VibrationEffect.createOneShot(500, VibrationEffect.DEFAULT_AMPLITUDE));
- }
- break;
- }
- }
- });
- mMediaRecorder.setOnErrorListener(new MediaRecorder.OnErrorListener() {
- @Override
- public void onError(MediaRecorder mr, int what, int extra) {
- Log.i(TAG, "ERROR: "+ what);
- if (what == MediaRecorder.MEDIA_ERROR_SERVER_DIED) {
- Log.i(TAG, "MediaRecorder.MEDIA_ERROR_SERVER_DIED");
- MainActivity.this.stopRecording();
- }
- }
- });
- try {
- mMediaRecorder.prepare();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement