天天看點

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.規範圖檔資源命名

一.效果展示

仿微信界面視訊錄制

RecorderManager安卓仿微信自定義音視訊錄制第三方庫
RecorderManager安卓仿微信自定義音視訊錄制第三方庫

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,有什麼建議或意見歡迎回報。