利用SurfaceView預覽視頻
利用系統自帶的MediaRecorder進行視頻錄製 關於MediaRecoreder的使用步驟在源碼註釋中寫的很是清楚php
// 錄製視頻
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實現java
<?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/…android
<?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.javagit
這裏直接copy Google官方示例中的代碼github
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;
}
}
複製代碼
RecordConfig.javabash
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;
}
}
複製代碼
!!!全部攝像頭及視頻錄製的操做應該異步處理app
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());
}
複製代碼
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();
}
複製代碼
源代碼:
SmallVideoRecord異步