RecorderManager
因为在项目中经常需要使用音视频录制,所以写了一个公共库 RecorderManager,欢迎大家使用。
最新 0.4.0-beta.5 版本: 1.升级依赖 2.移除 EasyPermissions 和废弃方法,使用新 API registerForActivityResult,请采用 Java1.8 以上版本 3.重构框架,优化代码 4.库调用做部分调整,详见下方文档说明 5.欢迎大家测试反馈完善功能
0.3.2 版本:1.移除 strings.xml 中 app_name 2.升级 kotlin
0.3.1 版本更新:详情见文档 1.新增最小录制时间设置 RecordVideoOption.setMinDuration(//最小录制时长(秒数,最小是 1,会自动调整不大于最大录制时长)) 2.优化代码
0.3-beta.2 版本更新: 1.重构项目代码,kotlin 改写部分功能 2.移除 rxjava 库,减少依赖 3.升级最新 SDK 4.新增闪光灯功能,增加计时前提示文本设置 5.增加国际化支持,英文和中文 6.修复已知问题,优化代码 7.对外用户调用 API 改动较少,主要为内部调整,见下方文档,欢迎大家测试反馈完善功能
0.2.29 版本更新: 1.新增圆形进度按钮配置功能 2.新增指定前后置摄像头功能 3.优化代码,调整启动视频录制配置项
0.2.28 版本更新: 1.优化视频录制结果获取方式 2.优化代码
0.2.27 版本更新: 1.视频录制界面 RecordVideoRequestOption 新增 RecorderOption 和 hideFlipCameraButton 配置 2.优化代码
0.2.26 版本更新: 1.项目迁移至 AndroidX, 引入 Kotlin
0.2.25 版本更新: 1.优化权限自动申请,可自动调起视频录制界面 2.规范图片资源命名
一.效果展示
仿微信界面视频录制
2.音频录制界面比较简单,就不放图了
二.引用
1.Add it in your root build.gradle at the end of repositories
allprojects {
repositories {
...
maven { url 'https://jitpack.io' }
}
}
2.Add the dependency
dependencies {
implementation 'com.github.MingYueChunQiu:RecorderManager:0.3.2'
}
三.使用
1.音频录制
采用默认配置录制
mRecorderManager.recordAudio(mFilePath);
自定义配置参数录制
mRecorderManager.recordAudio(new RecorderOption.Builder()
.setAudioSource(MediaRecorder.AudioSource.MIC)
.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4)
.setAudioEncoder(MediaRecorder.AudioEncoder.AAC)
.setAudioSamplingRate(44100)
.setBitRate(96000)
.setFilePath(path)
.build());
2.视频录制
(1).可以直接使用 RecordVideoActivity,实现了仿微信风格的录制界面
从 0.2.18 开始改为类似
RecorderManagerFactory.getRecordVideoRequest().startRecordVideo(MainActivity.this, 0);
从 0.4.0-beta 版本开始,因为采用 registerForActivityResult,所以直接传入结果回调
RecorderManagerProvider.getRecordVideoRequester().startRecordVideo(MainActivity.this, new RMRecordVideoResultCallback() {
@Override
public void onResponseRecordVideoResult(@NonNull RecordVideoResultInfo info) {
Log.e("MainActivity", "onActivityResult: " + info.getDuration() + " " + info.getFilePath());
Toast.makeText(MainActivity.this, info.getDuration() + " " + info.getFilePath(), Toast.LENGTH_SHORT).show();
}
@Override
public void onFailure(@NonNull RecorderManagerException e) {
Log.e("MainActivity", "onActivityResult: " + e.getErrorCode() + " " + e.getMessage());
}
});
从 0.4.0-beta 版本开始:RecorderManagerFactory 重命名为 RecorderManagerProvider RecorderManagerFactory 中可以拿到 IRecordVideoPageRequester,在 IRecordVideoPageRequester 接口中
/**
* 以默认配置打开录制视频界面
*
* @param activity Activity
* @param requestCode 请求码
*/
void startRecordVideo(@NonNull FragmentActivity activity, int requestCode);
/**
* 以默认配置打开录制视频界面
*
* @param fragment Fragment
* @param requestCode 请求码
*/
void startRecordVideo(@NonNull Fragment fragment, int requestCode);
/**
* 打开录制视频界面
*
* @param activity Activity
* @param requestCode 请求码
* @param option 视频录制请求配置信息类
*/
void startRecordVideo(@NonNull FragmentActivity activity, int requestCode, @Nullable RecordVideoRequestOption option);
/**
* 打开录制视频界面
*
* @param fragment Fragment
* @param requestCode 请求码
* @param option 视频录制请求配置信息类
*/
void startRecordVideo(@NonNull Fragment fragment, int requestCode, @Nullable RecordVideoRequestOption option);
从 0.4.0-beta 版本开始:
public interface IRecordVideoPageRequester extends IRMRequester {
/**
* 以默认配置打开录制视频界面
*
* @param activity Activity
* @param callback 视频录制结果回调
*/
void startRecordVideo(@NonNull FragmentActivity activity, @NonNull RMRecordVideoResultCallback callback);
/**
* 以默认配置打开录制视频界面
*
* @param fragment Fragment
* @param callback 视频录制结果回调
*/
void startRecordVideo(@NonNull Fragment fragment, @NonNull RMRecordVideoResultCallback callback);
/**
* 打开录制视频界面
*
* @param activity Activity
* @param option 视频录制请求配置信息类
* @param callback 视频录制结果回调
*/
void startRecordVideo(@NonNull FragmentActivity activity, @Nullable RecordVideoRequestOption option, @NonNull RMRecordVideoResultCallback callback);
/**
* 打开录制视频界面
*
* @param fragment Fragment
* @param option 视频录制请求配置信息类
* @param callback 视频录制结果回调
*/
void startRecordVideo(@NonNull Fragment fragment, @Nullable RecordVideoRequestOption option, @NonNull RMRecordVideoResultCallback callback);
}
RecordVideoRequestOption 可配置最大时长(秒)和文件保存路径
public class RecordVideoRequestOption implements Parcelable {
private String filePath;//文件保存路径
private int maxDuration;//最大录制时间(秒数)
private RecordVideoOption recordVideoOption;//录制视频配置信息类(里面配置的 filePath 和 maxDuration 会覆盖外面的)
}
RecordVideoActivity 里已经配置好了默认参数,可以直接使用,然后在 onActivityResult 里拿到视频路径的返回值 返回值为 RecordVideoResultInfo
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == Activity.RESULT_OK && requestCode == 0) {
RecordVideoResultInfo info = data.getParcelableExtra(EXTRA_RECORD_VIDEO_RESULT_INFO);
//从 0.2.28 版本开始可以使用下面这种方式,更安全更灵活,兼容性强
RecordVideoResultInfo info = RecorderManagerFactory.getRecordVideoResult(data);
//从 0.3 版本开始
RecordVideoResultInfo info = RecorderManagerFactory.getRecordVideoResultParser().parseRecordVideoResult(data);
if (info != null) {
Log.e("MainActivity", "onActivityResult: " + " "
+ info.getDuration() + " " + info.getFilePath());
}
}
}
从 0.4.0-beta.1 版本开始: 由于采用 Android 新 API registerForActivityResult,所以 startActivityForResult 等相关方法皆已废弃,相关回调将直接通过 RMRecordVideoResultCallback 传递
interface RMRecordVideoResultCallback {
fun onResponseRecordVideoResult(info: RecordVideoResultInfo)
fun onFailure(e: RecorderManagerException)
}
通过下列 IRecordVideoPageRequester 相关方法,调用时同时传入响应结果回调
void startRecordVideo(@NonNull FragmentActivity activity, @NonNull RMRecordVideoResultCallback callback);
(2).如果想要界面一些控件的样式,可以继承 RecordVideoActivity,里面提供了几个 protected 方法,可以拿到界面的一些控件
/**
* 获取计时控件
*
* @return 返回计时 AppCompatTextView
*/
protected AppCompatTextView getTimingView() {
return mRecordVideoFg == null ? null : mRecordVideoFg.getTimingView();
}
/**
* 获取圆形进度按钮
*
* @return 返回进度 CircleProgressButton
*/
protected CircleProgressButton getCircleProgressButton() {
return mRecordVideoFg == null ? null : mRecordVideoFg.getCircleProgressButton();
}
/**
* 获取翻转摄像头控件
*
* @return 返回翻转摄像头 AppCompatImageView
*/
public AppCompatImageView getFlipCameraView() {
return mRecordVideoFg == null ? null : mRecordVideoFg.getFlipCameraView();
}
/**
* 获取播放控件
*
* @return 返回播放 AppCompatImageView
*/
protected AppCompatImageView getPlayView() {
return mRecordVideoFg == null ? null : mRecordVideoFg.getPlayView();
}
/**
* 获取取消控件
*
* @return 返回取消 AppCompatImageView
*/
protected AppCompatImageView getCancelView() {
return mRecordVideoFg == null ? null : mRecordVideoFg.getCancelView();
}
/**
* 获取确认控件
*
* @return 返回确认 AppCompatImageView
*/
protected AppCompatImageView getConfirmView() {
return mRecordVideoFg == null ? null : mRecordVideoFg.getConfirmView();
}
/**
* 获取返回控件
*
* @return 返回返回 AppCompatImageView
*/
protected AppCompatImageView getBackView() {
return mRecordVideoFg == null ? null : mRecordVideoFg.getBackView();
}
想要替换图标资源的话,提供下列名称图片
rm_record_video_flip_camera.png
rm_record_video_cancel.png
rm_record_video_confirm.png
rm_record_video_play.png
rm_record_video_pull_down.png
rm_record_video_flashlight_turn_off.png
rm_record_video_flashlight_turn_on.png
(3).同时提供了对应的 RecordVideoFragment,实现与 RecordVideoActivity 同样的功能,实际 RecordVideoActivity 就是包裹了一个 RecordVideoFragment
1.创建 RecordVideoFragment
/**
* 获取录制视频 Fragment 实例(使用默认配置项)
*
* @param filePath 存储文件路径
* @return 返回 RecordVideoFragment
*/
public static RecordVideoFragment newInstance(@Nullable String filePath) {
return newInstance(filePath, 30);
}
/**
* 获取录制视频 Fragment 实例(使用默认配置项)
*
* @param filePath 存储文件路径
* @param maxDuration 最大时长(秒数)
* @return 返回 RecordVideoFragment
*/
public static RecordVideoFragment newInstance(@Nullable String filePath, int maxDuration) {
return newInstance(new RecordVideoOption.Builder()
.setRecorderOption(new RecorderOption.Builder().buildDefaultVideoBean(filePath))
.setMaxDuration(maxDuration)
.build());
}
/**
* 获取录制视频 Fragment 实例
*
* @param option 录制配置信息对象
* @return 返回 RecordVideoFragment
*/
public static RecordVideoFragment newInstance(@Nullable RecordVideoOption option) {
RecordVideoFragment fragment = new RecordVideoFragment();
Bundle args = new Bundle();
args.putParcelable(BUNDLE_EXTRA_RECORD_VIDEO_OPTION, option == null ? new RecordVideoOption() : option);
fragment.setArguments(args);
return fragment;
}
2.然后添加 RecordVideoFragment 到自己想要的地方就可以了 3.可以设置 OnRecordVideoListener,拿到各个事件的回调
public class RecordVideoOption:
private RecorderOption recorderOption;//录制配置信息
private RecordVideoButtonOption recordVideoButtonOption;//录制视频按钮配置信息类
private int minDuration;//最小录制时长(秒数,最小是 1,会自动调整不大于最大录制时长),可以和 timingHint 配合使用
private int maxDuration;//最大录制时间(秒数)
private RecorderManagerConstants.CameraType cameraType;//摄像头类型
private boolean hideFlipCameraButton;//隐藏返回翻转摄像头按钮
private boolean hideFlashlightButton;//隐藏闪光灯按钮
private String timingHint;//录制按钮上方提示语句(默认:0:%s),会在计时前显示
private String errorToastMsg;//录制发生错误 Toast(默认:录制时间小于 1 秒,请重试)
原 OnRecordVideoListener 现已改为 RMOnRecordVideoListener,并从 RecordVideoOption 中移除,主要用于用户自己 activity 或 fragment 实现此接口,用于承载 RecordVideoFragment,获取相关步骤回调
interface RMOnRecordVideoListener {
/**
* 当完成一次录制时回调
*
* @param filePath 视频文件路径
* @param videoDuration 视频时长(毫秒)
*/
fun onCompleteRecordVideo(filePath: String?, videoDuration: Int)
/**
* 当点击确认录制结果按钮时回调
*
* @param filePath 视频文件路径
* @param videoDuration 视频时长(毫秒)
*/
fun onClickConfirm(filePath: String?, videoDuration: Int)
/**
* 当点击取消按钮时回调
*
* @param filePath 视频文件路径
* @param videoDuration 视频时长(毫秒)
*/
fun onClickCancel(filePath: String?, videoDuration: Int)
/**
* 当点击返回按钮时回调
*/
fun onClickBack()
}
4.RecordVideoButtonOption 是圆形进度按钮配置类
private @ColorInt
int idleCircleColor;//空闲状态内部圆形颜色
private @ColorInt
int pressedCircleColor;//按下状态内部圆形颜色
private @ColorInt
int releasedCircleColor;//释放状态内部圆形颜色
private @ColorInt
int idleRingColor;//空闲状态外部圆环颜色
private @ColorInt
int pressedRingColor;//按下状态外部圆环颜色
private @ColorInt
int releasedRingColor;//释放状态外部圆环颜色
private int idleRingWidth;//空闲状态外部圆环宽度
private int pressedRingWidth;//按下状态外部圆环宽度
private int releasedRingWidth;//释放状态外部圆环宽度
private int idleInnerPadding;//空闲状态外部圆环与内部圆形之间边距
private int pressedInnerPadding;//按下状态外部圆环与内部圆形之间边距
private int releasedInnerPadding;//释放状态外部圆环与内部圆形之间边距
private boolean idleRingVisible;//空闲状态下外部圆环是否可见
private boolean pressedRingVisible;//按下状态下外部圆环是否可见
private boolean releasedRingVisible;//释放状态下外部圆环是否可见
5.RecorderOption 是具体的录制参数配置类
private int audioSource;//音频源
private int videoSource;//视频源
private int outputFormat;//输出格式
private int audioEncoder;//音频编码格式
private int videoEncoder;//视频编码格式
private int audioSamplingRate;//音频采样频率(一般 44100)
private int bitRate;//视频编码比特率
private int frameRate;//视频帧率
private int videoWidth, videoHeight;//视频宽高
private int maxDuration;//最大时长
private long maxFileSize;//文件最大大小
private String filePath;//文件存储路径
private int orientationHint;//视频录制角度方向
(4).如果想自定义自己的界面,可以直接使用 RecorderManagerable 类
1.通过 RecorderManagerFactory 获取 IRecorderManager 从 0.4.0-beta 版本开始:RecorderManagerFactory 重命名为 RecorderManagerProvider
public final class RecorderManagerProvider {
private RecorderManagerProvider() {
}
/**
* 创建录制管理类实例(使用默认录制类)
*
* @return 返回录制管理类实例
*/
@NonNull
public static IRecorderManager newInstance() {
return newInstance(new RecorderHelper());
}
/**
* 创建录制管理类实例(使用默认录制类)
*
* @param intercept 录制管理器拦截器
* @return 返回录制管理类实例
*/
@NonNull
public static IRecorderManager newInstance(@NonNull IRecorderManagerInterceptor intercept) {
return newInstance(new RecorderHelper(), intercept);
}
/**
* 创建录制管理类实例
*
* @param helper 实际录制类
* @return 返回录制管理类实例
*/
@NonNull
public static IRecorderManager newInstance(@NonNull IRecorderHelper helper) {
return newInstance(helper, null);
}
/**
* 创建录制管理类实例
*
* @param helper 实际录制类
* @param intercept 录制管理器拦截器
* @return 返回录制管理类实例
*/
@NonNull
public static IRecorderManager newInstance(@NonNull IRecorderHelper helper, @Nullable IRecorderManagerInterceptor intercept) {
return new RecorderManager(helper, intercept);
}
@NonNull
public static IRecordVideoPageRequester getRecordVideoRequester() {
return new RecordVideoPageRequester();
}
@NonNull
public static IRecordVideoResultParser getRecordVideoResultParser() {
return new RecordVideoResultParser();
}
}
它们返回的都是 IRecorderManager 接口类型,RecorderManager 是默认的实现类,RecorderManager 内持有一个真正进行操作的 RecorderHelper。
public interface IRecorderManager extends IRecorderHelper {
/**
* 设置录制对象
*
* @param helper 录制对象实例
*/
void setRecorderHelper(@NonNull IRecorderHelper helper);
/**
* 获取录制对象
*
* @return 返回录制对象实例
*/
@NonNull
IRecorderHelper getRecorderHelper();
/**
* 初始化相机对象
*
* @param holder Surface 持有者
* @return 返回初始化好的相机对象
*/
@Nullable
Camera initCamera(@NonNull SurfaceHolder holder);
/**
* 初始化相机对象
*
* @param cameraType 指定的摄像头类型
* @param holder Surface 持有者
* @return 返回初始化好的相机对象
*/
@Nullable
Camera initCamera(@NonNull RecorderManagerConstants.CameraType cameraType, @NonNull SurfaceHolder holder);
/**
* 打开或关闭闪光灯
*
* @param turnOn true 表示打开,false 关闭
*/
boolean switchFlashlight(boolean turnOn);
/**
* 翻转摄像头
*
* @param holder Surface 持有者
* @return 返回翻转并初始化好的相机对象
*/
@Nullable
Camera flipCamera(@NonNull SurfaceHolder holder);
/**
* 翻转到指定类型摄像头
*
* @param cameraType 摄像头类型
* @param holder Surface 持有者
* @return 返回翻转并初始化好的相机对象
*/
@Nullable
Camera flipCamera(@NonNull RecorderManagerConstants.CameraType cameraType, @NonNull SurfaceHolder holder);
/**
* 获取当前摄像头类型
*
* @return 返回摄像头类型
*/
@NonNull
RecorderManagerConstants.CameraType getCameraType();
/**
* 释放相机资源
*/
void releaseCamera();
}
RecorderManagerIntercept 实现 IRecorderManagerInterceptor 接口,用户可以直接继承 RecorderManagerIntercept,它里面所有方法都是空实现,可以自己改写需要的方法
public interface IRecorderManagerInterceptor extends ICameraInterceptor {
}
IRecorderHelper 是一个接口类型,由实现 IRecorderHelper 的子类来进行录制操作,默认提供的是 RecorderHelper,RecorderHelper 实现了 IRecorderHelper。
public interface IRecorderHelper {
/**
* 录制音频
*
* @param path 文件存储路径
* @return 返回是否成功开启录制,成功返回 true,否则返回 false
*/
boolean recordAudio(@NonNull String path);
/**
* 录制音频
*
* @param option 存储录制信息的对象
* @return 返回是否成功开启录制,成功返回 true,否则返回 false
*/
boolean recordAudio(@NonNull RecorderOption option);
/**
* 录制视频
*
* @param camera 相机
* @param surface 表面视图
* @param path 文件存储路径
* @return 返回是否成功开启录制,成功返回 true,否则返回 false
*/
boolean recordVideo(@Nullable Camera camera, @Nullable Surface surface, @Nullable String path);
/**
* 录制视频
*
* @param camera 相机
* @param surface 表面视图
* @param option 存储录制信息的对象
* @return 返回是否成功开启视频录制,成功返回 true,否则返回 false
*/
boolean recordVideo(@Nullable Camera camera, @Nullable Surface surface, @Nullable RecorderOption option);
/**
* 释放资源
*/
void release();
/**
* 获取录制器
*
* @return 返回实例对象
*/
@NonNull
MediaRecorder getMediaRecorder();
/**
* 获取配置信息对象
*
* @return 返回实例对象
*/
@Nullable
RecorderOption getRecorderOption();
}
2.拿到后创建相机对象
if (mCamera == null) {
mCamera = mManager.initCamera(mCameraType, svVideoRef.get().getHolder());
mCameraType = mManager.getCameraType();
}
3.录制
isRecording = mManager.recordVideo(mCamera, svVideoRef.get().getHolder().getSurface(), mOption.getRecorderOption());
4.释放
mManager.release();
mManager = null;
mCamera = null;
四.总结
目前来说,大体流程就是这样,更详细的信息请到 Github 上查看, 后期将添加闪光灯等更多功能,敬请关注,github 地址为 https://github.com/MingYueChunQiu/RecorderManager ,码云地址为 https://gitee.com/MingYueChunQiu/RecorderManager ,如果它能对你有所帮助,请帮忙点个 star,有什么建议或意见欢迎反馈。
