|
@@ -0,0 +1,243 @@
|
|
|
+package com.cooleshow.student.helper;
|
|
|
+
|
|
|
+import android.text.TextUtils;
|
|
|
+import android.util.Log;
|
|
|
+
|
|
|
+import com.cooleshow.base.callback.ResultCallback;
|
|
|
+import com.cooleshow.base.data.api.AppVersionApi;
|
|
|
+import com.cooleshow.base.data.api.DownloadApi;
|
|
|
+import com.cooleshow.base.data.net.RetrofitClientNoToken;
|
|
|
+import com.cooleshow.base.data.net.RetrofitFactory;
|
|
|
+import com.cooleshow.base.utils.FileUtils;
|
|
|
+import com.cooleshow.base.utils.Utils;
|
|
|
+import com.cooleshow.ffmpegcmd.FFmpegCmd;
|
|
|
+import com.cooleshow.ffmpegcmd.util.FFmpegUtil;
|
|
|
+
|
|
|
+import java.io.File;
|
|
|
+import java.io.FileNotFoundException;
|
|
|
+import java.io.FileOutputStream;
|
|
|
+import java.io.IOException;
|
|
|
+import java.io.InputStream;
|
|
|
+
|
|
|
+import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
|
|
|
+import io.reactivex.rxjava3.annotations.NonNull;
|
|
|
+import io.reactivex.rxjava3.core.Observable;
|
|
|
+import io.reactivex.rxjava3.core.ObservableEmitter;
|
|
|
+import io.reactivex.rxjava3.core.ObservableOnSubscribe;
|
|
|
+import io.reactivex.rxjava3.core.Observer;
|
|
|
+import io.reactivex.rxjava3.disposables.Disposable;
|
|
|
+import io.reactivex.rxjava3.schedulers.Schedulers;
|
|
|
+import okhttp3.ResponseBody;
|
|
|
+import retrofit2.Call;
|
|
|
+import retrofit2.Callback;
|
|
|
+import retrofit2.Response;
|
|
|
+
|
|
|
+/**
|
|
|
+ * Author by pq, Date on 2022/12/19.
|
|
|
+ */
|
|
|
+public class AccompanyHelper {
|
|
|
+ private static AccompanyHelper instance;
|
|
|
+ public static final String TAG = "AccompanyHelper";
|
|
|
+ public static final String BASE_PATH = FileUtils.getCacheDir(Utils.getApp(), "accompany");
|
|
|
+ public static final String accompanimentMp3Path = BASE_PATH + File.separator + "accompaniment.mp3";
|
|
|
+ public static final String videoMp3Path = BASE_PATH + File.separator + "videoBgm.mp3";
|
|
|
+ public static final String mergeMp3Path = BASE_PATH + File.separator + "merge.mp3";
|
|
|
+ public static final String onlyVideoPath = BASE_PATH + File.separator + "onlyVideoPath.mp4";
|
|
|
+ public static final String resultPathPath = BASE_PATH + File.separator + "result.mp4";
|
|
|
+
|
|
|
+ private AccompanyHelper() {
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ public static AccompanyHelper getInstance() {
|
|
|
+ if (instance == null) {
|
|
|
+ synchronized (AccompanyHelper.class) {
|
|
|
+ if (instance == null) {
|
|
|
+ instance = new AccompanyHelper();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return instance;
|
|
|
+ }
|
|
|
+
|
|
|
+ public void download(String url, ResultCallback<String> resultCallback) {
|
|
|
+ Observable.create(new ObservableOnSubscribe<String>() {
|
|
|
+ @Override
|
|
|
+ public void subscribe(@NonNull ObservableEmitter<String> emitter) throws Throwable {
|
|
|
+ FileUtils.delete(accompanimentMp3Path);
|
|
|
+ FileUtils.createOrExistsFile(accompanimentMp3Path);
|
|
|
+ File file = new File(accompanimentMp3Path);
|
|
|
+ downloadAccompany(url, file);
|
|
|
+ if (emitter != null) {
|
|
|
+ emitter.onNext(file.getAbsolutePath());
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }).subscribeOn(Schedulers.newThread())
|
|
|
+ .observeOn(AndroidSchedulers.mainThread())
|
|
|
+ .subscribe(new Observer<String>() {
|
|
|
+ @Override
|
|
|
+ public void onSubscribe(@NonNull Disposable d) {
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void onNext(@NonNull String s) {
|
|
|
+ if (resultCallback != null) {
|
|
|
+ resultCallback.onSuccess(s);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void onError(@NonNull Throwable e) {
|
|
|
+ e.printStackTrace();
|
|
|
+ if (resultCallback != null) {
|
|
|
+ resultCallback.onFail(-1, "download error");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void onComplete() {
|
|
|
+
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ private void downloadAccompany(String url, File file) {
|
|
|
+ if (TextUtils.isEmpty(url)) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ Response<ResponseBody> response = RetrofitClientNoToken.getInstance().getRetrofit().create(DownloadApi.class)
|
|
|
+ .download(url).execute();
|
|
|
+ if (response == null || response.body() == null) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ long total = response.body().contentLength();//需要下载的总大小
|
|
|
+ long current = 0;
|
|
|
+ InputStream inputStream = response.body().byteStream();
|
|
|
+ FileOutputStream fileOutputStream = new FileOutputStream(file);
|
|
|
+ byte[] bytes = new byte[1024];
|
|
|
+ int len = 0;
|
|
|
+ while ((len = inputStream.read(bytes)) != -1) {
|
|
|
+ fileOutputStream.write(bytes, 0, len);
|
|
|
+ fileOutputStream.flush();
|
|
|
+ current = current + len;
|
|
|
+ Log.e(TAG, "已经下载=" + current + " 需要下载=" + total);
|
|
|
+ }
|
|
|
+ fileOutputStream.flush();
|
|
|
+ fileOutputStream.close();
|
|
|
+ inputStream.close();
|
|
|
+ } catch (IOException e) {
|
|
|
+ e.printStackTrace();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public void startMix(String videoPath, String bgmPath, ResultCallback<String> resultCallback) {
|
|
|
+ Observable.create(new ObservableOnSubscribe<String>() {
|
|
|
+ @Override
|
|
|
+ public void subscribe(@NonNull ObservableEmitter<String> emitter) throws Throwable {
|
|
|
+ deleteAllTempFile();
|
|
|
+ Log.i(TAG, "转换开始");
|
|
|
+ int getVideoMp3Result = getVideoMp3_2(videoPath, videoMp3Path);
|
|
|
+ Log.i(TAG, "getVideoMp3 complete:" + getVideoMp3Result);
|
|
|
+ //mix原音和视频bgm mp3
|
|
|
+ Log.i(TAG, "mixMp3 start");
|
|
|
+ int mixMp3Result = mixMp3(bgmPath, videoMp3Path, mergeMp3Path);
|
|
|
+ Log.i(TAG, "mixMp3 complete:" + mixMp3Result);
|
|
|
+ //获取纯视频
|
|
|
+ int getOnlyVideoResult = getOnlyVideo(videoPath, onlyVideoPath);
|
|
|
+ Log.i(TAG, "extractVideo complete:" + getOnlyVideoResult);
|
|
|
+ //merge音频和视频
|
|
|
+ int mergeResult = megreMp3AndMp4(onlyVideoPath, mergeMp3Path, resultPathPath);
|
|
|
+ Log.i(TAG, "mergeMp4 complete:" + mergeResult);
|
|
|
+ Log.i(TAG, "转换完成");
|
|
|
+ if (emitter != null) {
|
|
|
+ boolean isSuccess = getVideoMp3Result == 0 && mixMp3Result == 0 && getOnlyVideoResult == 0 && mergeResult == 0;
|
|
|
+ Log.i(TAG, "转换是否全部isSuccess:" + isSuccess);
|
|
|
+ if (isSuccess) {
|
|
|
+ emitter.onNext(resultPathPath);
|
|
|
+ } else {
|
|
|
+ emitter.onNext(videoPath);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }).subscribeOn(Schedulers.newThread())
|
|
|
+ .observeOn(AndroidSchedulers.mainThread())
|
|
|
+ .subscribe(new Observer<String>() {
|
|
|
+ @Override
|
|
|
+ public void onSubscribe(@NonNull Disposable d) {
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void onNext(@NonNull String s) {
|
|
|
+ if (resultCallback != null) {
|
|
|
+ resultCallback.onSuccess(s);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void onError(@NonNull Throwable e) {
|
|
|
+ e.printStackTrace();
|
|
|
+ if (resultCallback != null) {
|
|
|
+ resultCallback.onFail(-1, "mix error");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void onComplete() {
|
|
|
+
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ private void deleteAllTempFile() {
|
|
|
+ FileUtils.delete(videoMp3Path);
|
|
|
+ FileUtils.delete(mergeMp3Path);
|
|
|
+ FileUtils.delete(onlyVideoPath);
|
|
|
+ FileUtils.delete(resultPathPath);
|
|
|
+ }
|
|
|
+
|
|
|
+ public int getVideoMp3_2(String videoPath, String outPath) {
|
|
|
+ //ffmpeg -i video.mp4 -vn audio.mp3
|
|
|
+ Log.i(TAG, "getVideoMp3 start videoPath:" + videoPath + "\noutPath:" + outPath);
|
|
|
+ String[] commands = new String[5];
|
|
|
+ commands[0] = "ffmpeg";
|
|
|
+ commands[1] = "-i";
|
|
|
+ commands[2] = videoPath;
|
|
|
+ commands[3] = "-vn";
|
|
|
+ commands[4] = outPath;
|
|
|
+ if (commands != null) {
|
|
|
+ return FFmpegCmd.executeSync(commands);
|
|
|
+ }
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ private int mixMp3(String audioPath, String bgmPath, String outputPath) {
|
|
|
+ String[] commands = FFmpegUtil.mixAudio(audioPath, bgmPath, outputPath);
|
|
|
+ if (commands != null) {
|
|
|
+ return FFmpegCmd.executeSync(commands);
|
|
|
+ }
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ private int getOnlyVideo(String videoPath, String out) {
|
|
|
+ Log.i(TAG, "extractVideo start");
|
|
|
+ String[] commands1 = FFmpegUtil.extractVideo(videoPath, out);
|
|
|
+ if (commands1 != null) {
|
|
|
+ return FFmpegCmd.executeSync(commands1);
|
|
|
+ }
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ private int megreMp3AndMp4(String videoPath, String mp3Path, String outPath) {
|
|
|
+ Log.i(TAG, "mergeMp4 start");
|
|
|
+ String[] commands = FFmpegUtil.mediaMux(videoPath, mp3Path, true, outPath);
|
|
|
+ if (commands != null) {
|
|
|
+ return FFmpegCmd.executeSync(commands);
|
|
|
+ }
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+}
|