短视频平台开发一个框架-短视频录制
效果图
原理说明
利用SurfaceView预览视频
利用系统自带的MediaRecorder进行视频录制 关于MediaRecoreder的使用步骤在源码注释中写的非常清楚
- 实例化
- 设置音频输入
- 设置输出格式
- 设置视频编码格式
- 设置输出路径
- 调用prepare()进行资源初始化
- 调用start()开始录制
注意: 这里的步骤先后顺序非常重要,如果对MediaRecorder不是那么熟悉,还是照着步骤写比较好
短视频平台开发一个框架-短视频录制使用方法
// 录制视频
private void toRecordVideo() {
RecordConfig
.getInstance()
.with(this)
.setQuality(RecordConfig.Quality.QUALITY_480P)
.setMaxDuration(6*1000)
.setFocusMode(RecordConfig.FocusMode.FOCUS_MODE_CONTINUOUS_VIDEO)
.setOutputPath("/smallvideo/")
.obtainVideo(REQUEST_CODE_VIDEO);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode==REQUEST_CODE_VIDEO&&resultCode==RESULT_OK){
//接收视频输出路径
String videoPath=RecordConfig.obtainVideoPath(data);
int duration=RecordConfig.obtainVideoDuration(data);
Log.i(this.getClass().getSimpleName(),"obtainVideoPath="+videoPath+" duration="+generateTime(duration));
}
}
复制代码
实现视频录制
新建录制与播放界面
录制界面
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".RecordVideoActivity">
<!--预览视频-->
<SurfaceView
android:id="@+id/surfaceView"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<!--录制按钮-->
<Button
android:id="@+id/btnRecord"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_marginBottom="60dp"
android:background="@drawable/selector_record_point"
app:layout_constraintBottom_toBottomOf="@+id/surfaceView"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent" />
<!--录制进度条-->
<com.junt.videorecorderlib.CustomProgressBar
android:id="@+id/progressBar"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_margin="5dp"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="@+id/btnRecord"
app:layout_constraintEnd_toEndOf="@+id/btnRecord"
app:layout_constraintStart_toStartOf="@+id/btnRecord"
app:layout_constraintTop_toTopOf="@+id/btnRecord"
app:ringWidth="10"
app:style="ring" />
<!--取消按钮-->
<ImageView
android:id="@+id/ivBack"
android:layout_width="50dp"
android:layout_height="50dp"
android:paddingStart="5dp"
android:paddingTop="10dp"
android:paddingEnd="5dp"
android:paddingBottom="10dp"
android:scaleType="fitXY"
android:src="@drawable/down"
app:layout_constraintBottom_toBottomOf="@+id/btnRecord"
app:layout_constraintEnd_toStartOf="@+id/btnRecord"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@+id/btnRecord" />
</androidx.constraintlayout.widget.ConstraintLayout>
录制按钮动画效果
内部白色按钮缩小放大利用selector实现
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true">
<layer-list>
<item android:drawable="@drawable/record_bg_recording" android:gravity="center" />
<item android:drawable="@drawable/record_fg_recording" android:gravity="center" />
</layer-list>
</item>
<item>
<layer-list>
<item android:drawable="@drawable/record_bg_default" android:gravity="center" />
<item android:drawable="@drawable/record_fg_default" android:gravity="center" />
</layer-list>
</item>
</selector>
复制代码
自定义圆形进度条: github.com/xiaojigugu/…
预览界面
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".PlayVideoActivity">
<!--自定义View播放视频-->
<com.junt.videorecorderlib.MediaPlayView
android:id="@+id/playView"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<!--取消-->
<ImageButton
android:id="@+id/btnGiveUp"
android:layout_width="80dp"
android:layout_height="80dp"
android:background="@drawable/selector_video_play_button"
android:src="@drawable/fanhui"
app:layout_constraintBottom_toTopOf="@+id/guideline2"
app:layout_constraintEnd_toStartOf="@+id/guideline"
app:layout_constraintHorizontal_bias="0.44"
app:layout_constraintStart_toStartOf="parent" />
<!--确定-->
<ImageButton
android:id="@+id/btnConfirm"
android:layout_width="80dp"
android:layout_height="80dp"
android:background="@drawable/selector_video_play_button"
android:src="@drawable/duigou"
app:layout_constraintBottom_toBottomOf="@+id/btnGiveUp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="@+id/guideline" />
<!--辅助线-->
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.5" />
<!--辅助线-->
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.9" />
</androidx.constraintlayout.widget.ConstraintLayout>
自定义MediaPlayView
继承SurfaceView,利用SurfaceHolder的回调方法进行MediaPlayer的初始化 MediaPlayView.java
新建相机管理类
这里直接copy Google官方示例中的代码
public class CameraHelper {
public static final int MEDIA_TYPE_IMAGE = 1;
public static final int MEDIA_TYPE_VIDEO = 2;
/**
* Iterate over supported camera video sizes to see which one best fits the
* dimensions of the given view while maintaining the aspect ratio. If none can,
* be lenient with the aspect ratio.
*
* @param supportedVideoSizes Supported camera video sizes.
* @param previewSizes Supported camera preview sizes.
* @param w The width of the view.
* @param h The height of the view.
* @return Best match camera video size to fit in the view.
*/
public static Camera.Size getOptimalVideoSize(List<Camera.Size> supportedVideoSizes,
List<Camera.Size> previewSizes, int w, int h) {
// Use a very small tolerance because we want an exact match.
final double ASPECT_TOLERANCE = 0.1;
double targetRatio = (double) w / h;
// Supported video sizes list might be null, it means that we are allowed to use the preview
// sizes
List<Camera.Size> videoSizes;
if (supportedVideoSizes != null) {
videoSizes = supportedVideoSizes;
} else {
videoSizes = previewSizes;
}
Camera.Size optimalSize = null;
// Start with max value and refine as we iterate over available video sizes. This is the
// minimum difference between view and camera height.
double minDiff = Double.MAX_VALUE;
// Target view height
int targetHeight = h;
// Try to find a video size that matches aspect ratio and the target view size.
// Iterate over all available sizes and pick the largest size that can fit in the view and
// still maintain the aspect ratio.
for (Camera.Size size : videoSizes) {
double ratio = (double) size.width / size.height;
if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE)
continue;
if (Math.abs(size.height - targetHeight) < minDiff && previewSizes.contains(size)) {
optimalSize = size;
minDiff = Math.abs(size.height - targetHeight);
}
}
// Cannot find video size that matches the aspect ratio, ignore the requirement
if (optimalSize == null) {
minDiff = Double.MAX_VALUE;
for (Camera.Size size : videoSizes) {
if (Math.abs(size.height - targetHeight) < minDiff && previewSizes.contains(size)) {
optimalSize = size;
minDiff = Math.abs(size.height - targetHeight);
}
}
}
return optimalSize;
}
/**
* @return the default camera on the device. Return null if there is no camera on the device.
*/
public static Camera getDefaultCameraInstance() {
return Camera.open();
}
/**
* @return the default rear/back facing camera on the device. Returns null if camera is not
* available.
*/
public static Camera getDefaultBackFacingCameraInstance() {
Log.i(CameraHelper.class.getSimpleName(),"getDefaultBackFacingCameraInstance");
return getDefaultCamera(Camera.CameraInfo.CAMERA_FACING_BACK);
}
/**
* @return the default front facing camera on the device. Returns null if camera is not
* available.
*/
public static Camera getDefaultFrontFacingCameraInstance() {
return getDefaultCamera(Camera.CameraInfo.CAMERA_FACING_FRONT);
}
/**
*
* @param position Physical position of the camera i.e Camera.CameraInfo.CAMERA_FACING_FRONT
* or Camera.CameraInfo.CAMERA_FACING_BACK.
* @return the default camera on the device. Returns null if camera is not available.
*/
@TargetApi(Build.VERSION_CODES.GINGERBREAD)
private static Camera getDefaultCamera(int position) {
// Find the total number of cameras available
int mNumberOfCameras = Camera.getNumberOfCameras();
// Find the ID of the back-facing ("default") camera
Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
for (int i = 0; i < mNumberOfCameras; i++) {
Camera.getCameraInfo(i, cameraInfo);
if (cameraInfo.facing == position) {
return Camera.open(i);
}
}
return null;
}
/**
* Creates a media file in the {@code Environment.DIRECTORY_PICTURES} directory. The directory
* is persistent and available to other applications like gallery.
*
* @param type Media type. Can be video or image.
* @return A file object pointing to the newly created file.
*/
public static File getOutputMediaFile(int type){
// To be safe, you should check that the SDCard is mounted
// using Environment.getExternalStorageState() before doing this.
if (!Environment.getExternalStorageState().equalsIgnoreCase(Environment.MEDIA_MOUNTED)) {
return null;
}
File mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_PICTURES), "CameraSample");
// This location works best if you want the created images to be shared
// between applications and persist after your app has been uninstalled.
// Create the storage directory if it does not exist
if (! mediaStorageDir.exists()){
if (! mediaStorageDir.mkdirs()) {
Log.d("CameraSample", "failed to create directory");
return null;
}
}
// Create a media file name
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.US).format(new Date());
File mediaFile;
if (type == MEDIA_TYPE_IMAGE){
mediaFile = new File(mediaStorageDir.getPath() + File.separator +
"IMG_"+ timeStamp + ".jpg");
} else if(type == MEDIA_TYPE_VIDEO) {
mediaFile = new File(mediaStorageDir.getPath() + File.separator +
"VID_"+ timeStamp + ".mp4");
} else {
return null;
}
return mediaFile;
}
}
复
新建MediaRecorder配置类
RecordConfig.java
public class RecordConfig {
private static RecordConfig recordConfig;
private Activity activity;
public static final String RECORD_CONFIG_SP_NAME = "RECORD_CONFIG";
private SharedPreferences sp;
static final String CONFIG_QUALITY = "quality";
static final String CONFIG_FOCUS_MODE = "focus_mode";
static final String CONFIG_ENCODING_BIT_RATE = "bitRate";
static final String CONFIG_FRAME_RATE = "frameRate";
static final String CONFIG_OUTPUT_PATH = "outputPath";
static final String CONFIG_MAX_DURATION = "duration";
public static RecordConfig getInstance() {
if (recordConfig == null) {
recordConfig = new RecordConfig();
}
return recordConfig;
}
<!--接收上下文-->
public RecordConfig with(Activity activity) {
this.activity = activity;
sp = activity.getSharedPreferences(RECORD_CONFIG_SP_NAME, Context.MODE_PRIVATE);
return this;
}
<!--视频质量-->
public RecordConfig setQuality(int quality) {
if (sp == null) {
throw new NullPointerException("Please innovate method 'with()' first");
}
//default:480P
sp.edit().putInt(CONFIG_QUALITY, quality).commit();
return this;
}
<!--对焦模式-->
public RecordConfig setFocusMode(String focusMode) {
if (sp == null) {
throw new NullPointerException("Please innovate method 'with()' first");
}
//default:FOCUS_MODE_CONTINUOUS_VIDEO
sp.edit().putString(CONFIG_FOCUS_MODE, focusMode).commit();
return this;
}
<!--音频采样率-->
public RecordConfig setEncodingBitRate(int encodingBitRate) {
if (sp == null) {
throw new NullPointerException("Please innovate method 'with()' first");
}
//default:5 * 1280 * 720
sp.edit().putInt(CONFIG_ENCODING_BIT_RATE, encodingBitRate).commit();
return this;
}
<!--视频帧率-->
public RecordConfig setFrameRate(int frameRate) {
if (sp == null) {
throw new NullPointerException("Please innovate method 'with()' first");
}
//default:20
sp.edit().putInt(CONFIG_FRAME_RATE, frameRate).commit();
return this;
}
/**
* 设置视频输出路径
* @param outputPath 视频输出路径默认前缀为 /storage/emulated/0
* eg:outputPath="/smallvideo/files/VID_timestamp.mp4",最终的文件路径为/storage/emulated/0/smallvideo/files/VID_timestamp.mp4
* @return RecordConfig
*/
public RecordConfig setOutputPath(String outputPath) {
if (sp == null) {
throw new NullPointerException("Please innovate method 'with()' first");
}
//default:/storage/emulated/0/junt/video/VID_timestamp.mp4
String path = Environment.getExternalStorageDirectory() + outputPath;
sp.edit().putString(CONFIG_OUTPUT_PATH, path).commit();
return this;
}
<!--设置最大时长-->
public RecordConfig setMaxDuration(int duration) {
if (sp == null) {
throw new NullPointerException("Please innovate method 'with()' first");
}
//default:6*1000ms
sp.edit().putInt(CONFIG_MAX_DURATION, duration).commit();
return this;
}
/**
* 获取视频路径
*/
public static String obtainVideoPath(Intent data){
if (data==null){
throw new NullPointerException("data is NULL");
}
return data.getStringExtra("path");
}
/**
* 获取视频长度
*/
public static int obtainVideoDuration(Intent data){
if (data==null){
throw new NullPointerException("data is NULL");
}
return data.getIntExtra("duration",0);
}
<!--跳转至视频录制界面-->
public void obtainVideo(int requestCode) {
if (activity == null) {
throw new NullPointerException("Please innovate method 'with()' first");
}
activity.startActivityForResult(new Intent(activity, RecordVideoActivity.class), requestCode);
}
<!--视频质量-->
public static class Quality {
public static int QUALITY_LOW = CamcorderProfile.QUALITY_LOW;
public static int QUALITY_HIGH = CamcorderProfile.QUALITY_HIGH;
public static int QUALITY_QCIF = CamcorderProfile.QUALITY_QCIF;
public static int QUALITY_CIF = CamcorderProfile.QUALITY_CIF;
public static int QUALITY_480P = CamcorderProfile.QUALITY_480P;
public static int QUALITY_720P = CamcorderProfile.QUALITY_720P;
public static int QUALITY_1080P = CamcorderProfile.QUALITY_1080P;
public static int QUALITY_QVGA = CamcorderProfile.QUALITY_QVGA;
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public static int QUALITY_2160P = CamcorderProfile.QUALITY_2160P;
}
<!--对焦模式-->
public static class FocusMode {
public static String FOCUS_MODE_AUTO = Camera.Parameters.FOCUS_MODE_AUTO;
public static String FOCUS_MODE_CONTINUOUS_PICTURE = Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE;
public static String FOCUS_MODE_CONTINUOUS_VIDEO = Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO;
public static String FOCUS_MODE_EDOF = Camera.Parameters.FOCUS_MODE_EDOF;
public static String FOCUS_MODE_INFINITY = Camera.Parameters.FOCUS_MODE_INFINITY;
public static String FOCUS_MODE_FIXED = Camera.Parameters.FOCUS_MODE_FIXED;
public static String FOCUS_MODE_MACRO = Camera.Parameters.FOCUS_MODE_MACRO;
}
}
新建RecordVideoActivity界面
!!!所有摄像头及视频录制的操作应该异步处理
- 初始化摄像头并预览
mCamera = Camera.open();
Log.d(TAG, "Camera.open");
//获取摄像头参数
Camera.Parameters parameters = mCamera.getParameters();
//获取所有预览尺寸
List<Camera.Size> mSupportedPreviewSizes = parameters.getSupportedPreviewSizes();
//获取所有的视频尺寸
List<Camera.Size> mSupportedVideoSizes = parameters.getSupportedVideoSizes();
//获取适当的尺寸
Camera.Size optimalSize = CameraHelper.getOptimalVideoSize(mSupportedVideoSizes,
mSupportedPreviewSizes, surfaceView.getWidth(), surfaceView.getHeight());
//设置预览竖屏方向
mCamera.setDisplayOrientation(90);
//获取系统默认配置
CamcorderProfile profile = CamcorderProfile.get(sp.getInt(RecordConfig.CONFIG_QUALITY, CamcorderProfile.QUALITY_480P));
//设置录制尺寸
profile.videoFrameWidth = optimalSize.width;
profile.videoFrameHeight = optimalSize.height;
//设置视频码率
profile.videoBitRate = sp.getInt(RecordConfig.CONFIG_ENCODING_BIT_RATE, 5 * 1280 * 720);
//设置视频帧率
profile.videoFrameRate = sp.getInt(RecordConfig.CONFIG_FRAME_RATE, 30);
//设置预览尺寸
parameters.setPreviewSize(profile.videoFrameWidth, profile.videoFrameHeight);
//设置对焦模式
parameters.setFocusMode(sp.getString(RecordConfig.CONFIG_FOCUS_MODE, Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO));
//设置闪光灯模式
parameters.setFlashMode(Camera.Parameters.FLASH_MODE_AUTO);
mCamera.setParameters(parameters);
try {
//绑定SurfaceView
mCamera.setPreviewDisplay(surfaceView.getHolder());
//开始预览
mCamera.startPreview();
Log.d(TAG, "Camera初始化结束");
} catch (IOException e) {
Log.e(TAG, "Surface texture is unavailable or unsuitable" + e.getMessage());
}
复制代码
- 初始化MediaRecorder
mMediaRecorder = new MediaRecorder();
//释放摄像头,以便让MediaRecorder能够使用它
// 该方法源码注释中明确表明必须提前调用
//* <p>This must be done before calling
//* {@link android.media.MediaRecorder#setCamera(Camera)}. This cannot be
//* called after recording starts.
//
mCamera.unlock();
//绑定摄像头
mMediaRecorder.setCamera(mCamera);
//设置音频来源
mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.DEFAULT);
//设置视频来源
mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
//设置录制视频质量
mMediaRecorder.setProfile(CamcorderProfile.get(sp.getInt(RecordConfig.CONFIG_QUALITY, CamcorderProfile.QUALITY_480P)));
//设置视频码率
mMediaRecorder.setVideoFrameRate(sp.getInt(RecordConfig.CONFIG_FRAME_RATE, 30));
//设置视频帧率
mMediaRecorder.setVideoEncodingBitRate(sp.getInt(RecordConfig.CONFIG_ENCODING_BIT_RATE, 5 * 1280 * 720));
//设置视频输出文件
String defaultPath = Environment.getExternalStorageDirectory() + "/junt/video/";
String outputPath = sp.getString(RecordConfig.CONFIG_OUTPUT_PATH, defaultPath) + "VID_" + System.currentTimeMillis() + ".mp4";
mOutputFile = new File(outputPath);
if (!mOutputFile.getParentFile().exists()) {
mOutputFile.getParentFile().mkdirs();
}
mMediaRecorder.setOutputFile(mOutputFile.getAbsolutePath());
//设置录制视频为竖屏
mMediaRecorder.setOrientationHint(90);
//设置录制时的预览Surface
mMediaRecorder.setPreviewDisplay(surfaceView.getHolder().getSurface());
//设置最大时长
//当设置次项以后可以在 android.media.MediaRecorder.OnInfoListener 监听回调方法中接收结果
// * After recording reaches the specified duration, a notification
//* will be sent to the {@link android.media.MediaRecorder.OnInfoListener}
//* with a "what" code of {@link #MEDIA_RECORDER_INFO_MAX_DURATION_REACHED}
//* and recording will be stopped.
MAX_DURATION = sp.getInt(RecordConfig.CONFIG_MAX_DURATION, 6 * 1000);
mMediaRecorder.setMaxDuration(MAX_DURATION);
try {
//设置录制监听
mMediaRecorder.setOnInfoListener(this);
//设置错误监听
mMediaRecorder.setOnErrorListener(this);
//完成初始化,等待录制
mMediaRecorder.prepare();
} catch (Exception e) {
Log.d(TAG, "IllegalStateException preparing MediaRecorder: " + e.getMessage());
return false;
}
//录制完成监听
@Override
public void onInfo(MediaRecorder mr, int what, int extra) {
Log.d(TAG, "onInfo what=" + what + " extra=" + extra);
if (what == MediaRecorder.MEDIA_RECORDER_INFO_MAX_DURATION_REACHED && isRecording) {
recordComplete();
}
}
```
注意:步骤1-2中的所有操作都是异步的
``` java
class MediaPrepareTask extends AsyncTask<Void, Void, Boolean> {
@Override
protected Boolean doInBackground(Void... voids) {
//初始化操作,包括初始化Camera、MediaRecorder
boolean initResult = prepareVideoRecorder();
Log.d(TAG, "doInBackground,init:" + initResult);
if (initResult) {
Log.d(TAG, "开始预览");
return true;
} else {
Log.d(TAG, "初始化错误");
//初始化错误则立即释放Camera、MediaRecorder
releaseMediaRecorder();
return false;
}
}
}
复制代码
- 录制按钮事件
/**
* 录制按钮触摸事件
* 单击录制(再次单击停止录制)、按住录制(松手停止录制)
*/
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
int action = motionEvent.getAction();
if (action == MotionEvent.ACTION_DOWN) {
//按下
long downTime=System.currentTimeMillis();
if (downTime-clickTime>1000){
if (!isRecording){
btnRecord.setPressed(true);
//开始录制
RecordTask recordTask = new RecordTask();
recordTask.execute();
}else if (mMediaRecorder!=null){
recordComplete();
}
}
clickTime=downTime;
} else if (action == MotionEvent.ACTION_UP) {
//抬起
if (isRecording && mMediaRecorder != null) {
//停止录制
recordComplete();
}
}
return true;
}
/**
* 开始录制任务
*/
class RecordTask extends AsyncTask<Void, Void, Boolean> {
@Override
protected Boolean doInBackground(Void... voids) {
mMediaRecorder.start();
return true;
}
@Override
protected void onPostExecute(Boolean aBoolean) {
super.onPostExecute(aBoolean);
isRecording = true;
//更新圆形进度条
setProgressBar();
}
}
/**
* 停止录制
*/
private void recordComplete() {
isRecording = false;
btnRecord.setPressed(false);
endTime = System.currentTimeMillis();
hideRecordController();
//跳转到视频播放界面进行完整预览,在onActivityResult中接收是否使用该视频文件的结果
Intent intent = new Intent(RecordVideoActivity.this, PlayVideoActivity.class);
intent.putExtra(VIDEO_PATH, mOutputFile.getAbsolutePath());
startActivityForResult(intent, REQUEST_CODE_TO_PLAY);
}
/**
* 设置进度条显示并调整其大小
*/
private void setProgressBar() {
progressBar.setProgress(0);
ConstraintLayout.LayoutParams params = (ConstraintLayout.LayoutParams) progressBar.getLayoutParams();
params.width = btnRecord.getMeasuredWidth() + 20;
params.height = btnRecord.getMeasuredHeight() + 20;
progressBar.setLayoutParams(params);
progressBar.setVisibility(View.VISIBLE);
startTime = System.currentTimeMillis
//利用计时器定时更新进度条
progressHandler = new ProgressHandler();
new Timer().schedule(new TimerTask() {
@Override
public void run() {
if (progressHandler != null && isRecording) {
progressHandler.sendEmptyMessage(0);
}
}
}, 0, 50);
}
/**
* 更新进度条
*/
class ProgressHandler extends Handler {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
if (msg.what == 0) {
int progress = (int) ((System.currentTimeMillis() - startTime) / (MAX_DURATION / 100));
if (progress <= 100) {
progressBar.setProgress(progress);
}
}
}
}
/**
* 接收用户确认时事件
* @param requestCode 跳转播放请求码
* @param resultCode 结果码
* @param data 传递了duration
*/
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_CODE_TO_PLAY) {
if (resultCode == RESULT_CANCELED) {
//用户选择取消,重置视频录制界面(进度条、播放按钮)
resetProgress();
showRecordController();
//删除被放弃的视频
deleteFile();
} else if (resultCode == RESULT_OK) {
//用户选择了该视频,将结果返回给调用方
Intent intent = new Intent();
intent.putExtra("duration", data.getIntExtra("duration", 0));
intent.putExtra("path", mOutputFile.getAbsolutePath());
setResult(RESULT_OK, intent);
finish();
}
}
}
播放界面
/**
* 放弃该视频
*/
private void giveUp() {
setResult(RESULT_CANCELED);
finish();
}
/**
* 选择该视频
*/
private void chooseThisVideo() {
Intent intent = new Intent();
intent.putExtra("duration", mediaPlayView.getDuration());
Log.i(TAG,"duration="+mediaPlayView.getDuration());
setResult(RESULT_OK, intent);
finish();
}