原理说明

利用SurfaceView预览视频
利用系统自带的MediaRecorder实现短视频app源码中短视频视频的录制

  1. 实例化
  2. 设置音频输入
  3. 设置输出格式
  4. 设置视频编码格式
  5. 设置输出路径
  6. 调用prepare()进行资源初始化
  7. 调用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);}@Overrideprotected 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"><!--预览视频--><SurfaceViewandroid: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" /><!--录制按钮--><Buttonandroid: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.CustomProgressBarandroid: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" /><!--取消按钮--><ImageViewandroid: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.MediaPlayViewandroid:id="@+id/playView"android:layout_width="match_parent"android:layout_height="match_parent"/><!--取消--><ImageButtonandroid: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" /><!--确定--><ImageButtonandroid: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.Guidelineandroid: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.Guidelineandroid: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的初始化

新建相机管理类

这里直接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// sizesList<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 heightint 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 requirementif (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 availableint  mNumberOfCameras = Camera.getNumberOfCameras();// Find the ID of the back-facing ("default") cameraCamera.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 existif (! mediaStorageDir.exists()){if (! mediaStorageDir.mkdirs()) {Log.d("CameraSample", "failed to create directory");return null;}}// Create a media file nameString 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:480Psp.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_VIDEOsp.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 * 720sp.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:20sp.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.mp4String 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*1000mssp.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界面

!!!所有摄像头及视频录制的操作应该异步处理

  1. 初始化摄像头并预览
        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 {//绑定SurfaceViewmCamera.setPreviewDisplay(surfaceView.getHolder());//开始预览mCamera.startPreview();Log.d(TAG, "Camera初始化结束");} catch (IOException e) {Log.e(TAG, "Surface texture is unavailable or unsuitable" + e.getMessage());}
复制代码
  1. 初始化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);//设置录制时的预览SurfacemMediaRecorder.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;}   //录制完成监听@Overridepublic 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中的所有操作都是异步的
``` javaclass MediaPrepareTask extends AsyncTask<Void, Void, Boolean> {@Overrideprotected Boolean doInBackground(Void... voids) {//初始化操作,包括初始化Camera、MediaRecorderboolean initResult = prepareVideoRecorder();Log.d(TAG, "doInBackground,init:" + initResult);if (initResult) {Log.d(TAG, "开始预览");return true;} else {Log.d(TAG, "初始化错误");//初始化错误则立即释放Camera、MediaRecorderreleaseMediaRecorder();return false;}}}
复制代码
  1. 录制按钮事件
    /*** 录制按钮触摸事件* 单击录制(再次单击停止录制)、按住录制(松手停止录制)*/@Overridepublic 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> {@Overrideprotected Boolean doInBackground(Void... voids) {mMediaRecorder.start();return true;}@Overrideprotected 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() {@Overridepublic void run() {if (progressHandler != null && isRecording) {progressHandler.sendEmptyMessage(0);}}}, 0, 50);}/*** 更新进度条*/class ProgressHandler extends Handler {@Overridepublic 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*/@Overrideprotected 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();}
复制代码

完结

短视频app源码开发,短视频录制的实现相关推荐

  1. 短视频app源码开发,音视频合成的实现

    在短视频app源码开发中,音视频数据的处理是关键,尤其是音视频合成处理,只有有声音的短视频内容才更有吸引力,在短视频app源码中如何实现音视频的合成呢? 音频合成 调用方法 //音视频合成func a ...

  2. 短视频app源码开发,音视频混合的实现

    在短视频app源码开发中,音视频的混合是对音视频数据进行处理时,非常重要的一个环节,只有做好了音视频混合,才能录制更好的短视频内容. //音视频合成 func videoAudioMerge() {/ ...

  3. 短视频app源码开发:仿抖音短视频热门页面的实现

    在短视频app源码开发中,仿抖音短视频热门页面的实现只不过是多了一个由UICollectionView呈现多个视频图片的中间界面,点开后播放视频界面其实就是推荐界面,所以这里并没有什么核心难点,只是简 ...

  4. 短视频app源码、小视频源码存储功能如何实现?

    在短视频app源码(小视频源码)开发中,考虑到后期用户上传短视频时需要大量应用到存储功能,故而需要实现这一功能,具体需要怎么做呢,本文将以云豹短视频app源码为例,为大家进行讲解. 一.阅读前请注意: ...

  5. 小视频app源码开发不可忽视的重点在这里

    小视频app适合各种移动场景下的用户参与,以内容为卖点,通过大数据功能筛选市场喜爱的视频,实际操作简单,容易引发二次传播,且变现模式成熟,因此,在抖音.微信等小视频app的刺激下,小视频app源码开发 ...

  6. 用成品短视频App源码开发您的下一个创意项目

    您是否曾经有过一个创意项目,但是不知道如何实现?成品短视频App源码可以帮助您快速开发出一个小视频App.本文将介绍如何使用成品短视频App源码来开发您的下一个创意项目. 什么是成品短视频App源码? ...

  7. 短视频app源码开发,短视频平台框架搭建

    科技发展,技术进步,音视频异军突起.无视频,不网络,短视频成为最重要的信息载体之一,是互联网核心组成部分.构建高效的短视频app源码,是慎之又慎的问题.从架构的角度,探讨短视频app源码的构建与技术选 ...

  8. 短视频app源码:yoo视频更名火锅视频,开启长带短新模式

    文/布谷安妮来源/山东布谷鸟网络 网络视频时代的到来,不仅意味着平台为草根创意人才获得成功提供了渠道,而且也有助于重新提振音乐工业.电影工业.电视工业甚至竞技体育产业的发展水平.无论是在美国.中国还是 ...

  9. 如何开发仿抖音短视频APP源码?

    如何开发仿抖音短视频APP源码? 流程列表 开发一个短视频最主要的流程分为 3 个,下面我将分步教你实现这 3 个流程下的各个功能点,功能点 API 可按需调用: 视频拍摄 a.启动拍摄 b.给拍摄添 ...

最新文章

  1. c语言计算正方体表面积的程序,成都信息工程学院C语言考试题及答案
  2. Java:四种取整的方法
  3. 为什么 HTTPS 是安全的?
  4. 最大公约数和最小公倍数 模板
  5. 「3.4w字」超保姆级教程带你实现Promise的核心功能
  6. python羊车门问题_「羊车门」经典概率题中不换门选中车的概率是多少?
  7. oracle 出参类型定义,Oracle plsql出参clob类型的操作
  8. OJ1033: 五级制成绩
  9. Docker上部署MariaDB
  10. vim linux python3,centos7 python3.7+vim8
  11. 一键登录163邮箱方法
  12. js:获取今天是星期几
  13. PHP是TM最美的语言,我的文章是最棒的狗粮
  14. 什么是真正的转运?常见的五种转运方法
  15. 计算机课还无聊吗,《快乐星球Ⅴ》电脑课还可以这样?
  16. 6 --> MAC层协议
  17. 打开新世界的大门——初识c语言
  18. 国产化适配之人大金仓数据库(二)数据迁移
  19. 《Spring实战》读书笔记-第3章 高级装配
  20. Java编程之学生类

热门文章

  1. 数据传输性能与安全不能兼顾?Rambus安全方案“动静”两相宜
  2. CVPR2022 Oral:StreamYOLO-流感知实时检测器
  3. 软件测试基础知识 - 单元测试、集成测试、系统测试、回归测试、验收测试这几步中最重要的是哪一步
  4. Python | Flask 解决跨域问题
  5. 第8章 中医证型关联规则挖掘代码调整
  6. 精品微信小程序校园第二课堂在线学习网+后台系统|前后分离VUE
  7. 使用存储过程返回结果集
  8. 成功将TTF字体从18M裁剪到1.8M
  9. java计算机毕业设计BS用户小票系统(附源码、数据库)
  10. 2019手机CPU芯片性能天梯图