Last active
November 9, 2022 07:01
-
-
Save shaobin0604/8e73e4eeceeb105566b761ba0df517fe to your computer and use it in GitHub Desktop.
Mix Video with vocal audio and music audio using ffmpeg
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.arthenica.ffmpegkit.test; | |
import static com.arthenica.ffmpegkit.test.MainActivity.TAG; | |
import static com.arthenica.ffmpegkit.test.MainActivity.notNull; | |
import android.os.Bundle; | |
import android.os.Environment; | |
import android.text.method.ScrollingMovementMethod; | |
import android.util.Log; | |
import android.view.View; | |
import android.widget.Button; | |
import android.widget.TextView; | |
import androidx.annotation.NonNull; | |
import androidx.annotation.Nullable; | |
import androidx.fragment.app.Fragment; | |
import com.arthenica.ffmpegkit.FFmpegKit; | |
import com.arthenica.ffmpegkit.ReturnCode; | |
import java.io.File; | |
public class SlimScreenRecordTabFragment extends Fragment { | |
private static final String VOCAL_AUDIO_URL = "https://example.com/audio/vocal.mp3"; | |
private static final String MUSIC_AUDIO_URL = "https://example.com/audio/music.mp3"; | |
private static final String VIDEO_FILE_NAME = "record-1667288804378.ts"; | |
private TextView outputText; | |
public static SlimScreenRecordTabFragment newInstance() { | |
return new SlimScreenRecordTabFragment(); | |
} | |
public SlimScreenRecordTabFragment() { | |
super(R.layout.fragment_slim_screen_record_tab); | |
} | |
@Override | |
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { | |
super.onViewCreated(view, savedInstanceState); | |
Button runButton = view.findViewById(R.id.runButton); | |
runButton.setOnClickListener(new View.OnClickListener() { | |
@Override | |
public void onClick(View v) { | |
runTest(); | |
} | |
}); | |
outputText = view.findViewById(R.id.outputText); | |
outputText.setMovementMethod(new ScrollingMovementMethod()); | |
} | |
private void runTest() { | |
clearOutput(); | |
final File sdcardRoot = Environment.getExternalStorageDirectory(); | |
final String inVideoPath = new File(sdcardRoot, VIDEO_FILE_NAME).getAbsolutePath(); | |
final String outVideoPath = new File(sdcardRoot, "out.mp4").getAbsolutePath(); | |
final String ffmpegCommand = String.format("-hide_banner -y " | |
+ "-i \"%s\" " | |
+ "-i \"%s\" " | |
+ "-i \"%s\" " | |
+ "-filter_complex \"[1:a][2:a]amix=inputs=2:duration=longest:dropout_transition=0:weights='1 0.5':normalize=0[a]\" " | |
+ "-map \"0:v\" -map \"[a]\" " | |
+ "-c:v \"copy\" -c:a \"aac\" " | |
+ "-f \"mp4\" \"%s\"", inVideoPath, VOCAL_AUDIO_URL, MUSIC_AUDIO_URL, outVideoPath); | |
Log.d(TAG, String.format("FFmpeg process started with arguments: '%s'.", ffmpegCommand)); | |
FFmpegKit.executeAsync(ffmpegCommand, session -> { | |
Log.d(TAG, String.format("FFmpeg process exited with state %s and rc %s.%s", session.getState(), | |
session.getReturnCode(), notNull(session.getFailStackTrace(), "\n"))); | |
MainActivity.addUIAction(() -> { | |
if (ReturnCode.isSuccess(session.getReturnCode())) { | |
Popup.show(requireContext(), "ffmpeg completed successfully."); | |
} else { | |
Popup.show(requireContext(), "ffmpeg failed. Please check logs for the details."); | |
} | |
}); | |
}, log -> MainActivity.addUIAction(() -> { | |
appendOutput(log.getMessage()); | |
}), statistics -> { | |
Log.d(TAG, statistics.toString()); | |
}); | |
} | |
public void appendOutput(final String logMessage) { | |
outputText.append(logMessage); | |
} | |
public void clearOutput() { | |
outputText.setText(""); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# command on desktop | |
ffmpeg \ | |
-i <video mp4> \ | |
-i <vocal mp3> \ | |
-i <background music mp3> \ | |
-filter_complex "[1:a][2:a]amix=inputs=2:duration=longest:dropout_transition=0:weights='1 0.5':normalize=0[a]" \ | |
-map "0:v" -map "[a]" \ | |
-c:v "copy" -c:a "aac" \ | |
-f "mp4" "out.mp4" | |
# see: | |
# - https://stackoverflow.com/questions/14498539/how-to-overlay-downmix-two-audio-files-using-ffmpeg | |
# - https://blog.nytsoi.net/2017/12/31/ffmpeg-combining-audio-tracks | |
# - https://gist.github.com/LukasKnuth/4d7ee6812ccb221b2775e984516b56d4 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
4分12 秒 1080p 30fps 视频,文件大小:107M
ffmpeg 处理耗时:15秒,CPU 占用:100%(即把一核占满),内存 约1%