Skip to content

Commit

Permalink
add share video
Browse files Browse the repository at this point in the history
  • Loading branch information
aquamarine5 committed Apr 9, 2022
1 parent 5327557 commit 641ee7d
Show file tree
Hide file tree
Showing 6 changed files with 169 additions and 94 deletions.
1 change: 1 addition & 0 deletions .idea/misc.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

18 changes: 15 additions & 3 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.aquaapps.readtorecite">

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.CAMERA"/>
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="28"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />

<application
android:allowBackup="true"
Expand All @@ -24,6 +26,16 @@
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>

<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.fileProvider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>
</application>

</manifest>
102 changes: 102 additions & 0 deletions app/src/main/java/com/aquaapps/readtorecite/CameraController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
package com.aquaapps.readtorecite;

import android.Manifest;
import android.content.ContentValues;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Build;
import android.provider.MediaStore;

import androidx.appcompat.app.AppCompatActivity;
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.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import androidx.core.util.Consumer;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.concurrent.ExecutionException;


public class CameraController {
public PreviewView previewView;
public ProcessCameraProvider cameraProvider;
public Recorder recorder;
public Recording recording = null;
public VideoCapture<Recorder> videoCapture;
public AppCompatActivity activity;

public CameraController(AppCompatActivity activity) {
this.activity = activity;
try {
cameraProvider = ProcessCameraProvider.getInstance(activity).get();
Preview preview = new Preview.Builder().build();
previewView = activity.findViewById(R.id.previewView);
CameraSelector cameraSelector = new CameraSelector.Builder()
.requireLensFacing(CameraSelector.LENS_FACING_FRONT)
.build();
preview.setSurfaceProvider(previewView.getSurfaceProvider());

QualitySelector qs = QualitySelector.fromOrderedList(
QualitySelector.getSupportedQualities(
cameraSelector.filter(cameraProvider.getAvailableCameraInfos()).get(0)),
FallbackStrategy.higherQualityOrLowerThan(Quality.SD));
recorder = new Recorder.Builder()
.setQualitySelector(qs)
.build();
videoCapture = VideoCapture.withOutput(recorder);
cameraProvider.bindToLifecycle(activity, cameraSelector, videoCapture, preview);

} catch (ExecutionException | InterruptedException e) {
e.printStackTrace();
}
}

public boolean isRecording() {
return recording != null;
}

public void startRecord(Consumer<VideoRecordEvent> videoRecordListener) {
ContentValues values = new ContentValues();
values.put(MediaStore.MediaColumns.DISPLAY_NAME,
"ReadToRecite-" + new SimpleDateFormat("yyyyMMdd-HHmmss", Locale.ENGLISH).format(new Date())+".3gp");
Uri videoCollection;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
videoCollection = MediaStore.Video.Media
.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY);
} else {
videoCollection = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
}
MediaStoreOutputOptions options = new MediaStoreOutputOptions.Builder(
activity.getContentResolver(), videoCollection)
.setContentValues(values)
.build();

if (ActivityCompat.checkSelfPermission(activity, Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(activity, new String[]{Manifest.permission.RECORD_AUDIO}, 114514);
}

recording = videoCapture.getOutput()
.prepareRecording(activity, options)
.withAudioEnabled()
.start(ContextCompat.getMainExecutor(activity), videoRecordListener);
}

public void stopRecord() {
recording.stop();
recording = null;
}

}
134 changes: 44 additions & 90 deletions app/src/main/java/com/aquaapps/readtorecite/MainActivity.java
Original file line number Diff line number Diff line change
@@ -1,51 +1,26 @@
package com.aquaapps.readtorecite;

import android.Manifest;
import android.content.ClipData;
import android.content.ContentValues;
import android.content.pm.PackageManager;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.provider.MediaStore;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Toast;

import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
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.FileOutputOptions;
import androidx.camera.video.MediaStoreOutputOptions;
import androidx.camera.video.OutputOptions;
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.OutputResults;
import androidx.camera.video.VideoRecordEvent;
import androidx.camera.view.PreviewView;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;

import com.google.android.material.floatingactionbutton.FloatingActionButton;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.concurrent.ExecutionException;
import java.util.Arrays;

public class MainActivity extends AppCompatActivity {
public PreviewView previewView;
public ProcessCameraProvider cameraProvider;
public Recorder recorder;
public Recording recording=null;
public VideoCapture<Recorder> videoCapture;
public CameraController cameraController;

public boolean isShowingPreview=true;
public boolean isShowingPreview = true;

@Override
protected void onCreate(Bundle savedInstanceState) {
Expand All @@ -55,63 +30,27 @@ protected void onCreate(Bundle savedInstanceState) {
setSupportActionBar(toolbar);
FloatingActionButton fab = findViewById(R.id.fab);
fab.setOnClickListener(view -> {
if(recording==null) {
// Start record
ContentValues values = new ContentValues();
values.put(MediaStore.Video.Media.DISPLAY_NAME,
"ReadToRecite-" + new SimpleDateFormat("yyyyMMdd-HHmmss", Locale.ENGLISH).format(new Date()) + ".mp4");
MediaStoreOutputOptions options = new MediaStoreOutputOptions.Builder(
this.getContentResolver(), MediaStore.Video.Media.EXTERNAL_CONTENT_URI)
.setContentValues(values)
.build();
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.RECORD_AUDIO}, 114514);
}

recording = videoCapture.getOutput().prepareRecording(this, options)
.withAudioEnabled()
.start(ContextCompat.getMainExecutor(this), videoRecordEvent -> {
if(videoRecordEvent instanceof VideoRecordEvent.Finalize){
VideoRecordEvent.Finalize finalizeEvent= (VideoRecordEvent.Finalize) videoRecordEvent;
Log.e("Debug", String.valueOf(finalizeEvent.getError()));
OutputOptions outputOptions=finalizeEvent.getOutputOptions();
if(outputOptions instanceof FileOutputOptions)
Log.e("Debug",((FileOutputOptions) outputOptions).getFile().getAbsolutePath());
}
});

fab.setImageResource(android.R.drawable.ic_menu_save);

} else { // Stop record
recording.stop();
recording=null;
if (cameraController.isRecording()) {
cameraController.stopRecord();
fab.setImageResource(android.R.drawable.ic_media_play); // start
} else {
cameraController.startRecord(videoRecordEvent -> {
if (videoRecordEvent instanceof VideoRecordEvent.Finalize) {
VideoRecordEvent.Finalize finalizeEvent = (VideoRecordEvent.Finalize) videoRecordEvent;
OutputResults outputResults = finalizeEvent.getOutputResults();
int errorCode = finalizeEvent.getError();
if (errorCode != VideoRecordEvent.Finalize.ERROR_NONE) {
Toast.makeText(this, "错误: " + errorCode, Toast.LENGTH_LONG).show();
} else {
shareVideo(outputResults.getOutputUri());
}
}
});
fab.setImageResource(android.R.drawable.ic_menu_save);
}
});
// Instance Camera
try{
cameraProvider=ProcessCameraProvider.getInstance(this).get();
Preview preview=new Preview.Builder().build();
previewView=findViewById(R.id.previewView);
CameraSelector cameraSelector=new CameraSelector.Builder()
.requireLensFacing(CameraSelector.LENS_FACING_FRONT)
.build();
preview.setSurfaceProvider(previewView.getSurfaceProvider());

QualitySelector qs=QualitySelector.fromOrderedList(
QualitySelector.getSupportedQualities(
cameraSelector.filter(cameraProvider.getAvailableCameraInfos()).get(0)),
FallbackStrategy.higherQualityOrLowerThan(Quality.SD));
recorder=new Recorder.Builder()
.setQualitySelector(qs)
.build();
videoCapture=VideoCapture.withOutput(recorder);
Camera camera=cameraProvider.bindToLifecycle(this,cameraSelector,videoCapture,preview);

}
catch(ExecutionException | InterruptedException e){
e.printStackTrace();
}
cameraController = new CameraController(this);
}


Expand All @@ -131,17 +70,32 @@ public boolean onOptionsItemSelected(MenuItem item) {

//noinspection SimplifiableIfStatement
if (id == R.id.action_preview) {
if(isShowingPreview){
previewView.setVisibility(View.INVISIBLE);
if (isShowingPreview) {
cameraController.previewView.setVisibility(View.INVISIBLE);
item.setTitle(R.string.action_preview_enabled);
} else{
previewView.setVisibility(View.VISIBLE);
} else {
cameraController.previewView.setVisibility(View.VISIBLE);
item.setTitle(R.string.action_preview_disabled);
}
isShowingPreview=!isShowingPreview;
isShowingPreview = !isShowingPreview;
return true;
}

return super.onOptionsItemSelected(item);
}

public void shareVideo(Uri videoUri) {
Intent intent = new Intent();
intent.setAction(Intent.ACTION_SEND);
String[] splitResult = videoUri.getPath().split("\\.");
if (splitResult[splitResult.length - 1].equals("3gp")) {
intent.setType("video/3gpp");
} else {
intent.setType("video/mp4");
}

intent.putExtra(Intent.EXTRA_STREAM, videoUri);
startActivity(Intent.createChooser(intent, "分享..."));
}

}
2 changes: 1 addition & 1 deletion app/src/main/res/drawable/background_gradient.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<gradient
android:startColor="@color/colorLightPink"
android:endColor="@color/colorLightBlue"/>
android:endColor="@color/colorLightBlue" />
</shape>
6 changes: 6 additions & 0 deletions app/src/main/res/xml/file_paths.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<paths>
<external-path
name="external_storage_root"
path="." />
</paths>

0 comments on commit 641ee7d

Please sign in to comment.