使用ffmpeg合并两个音频文件和一个视频文件并控制音量



我想使用ffmpeg将两个音频文件与一个视频文件合并,以创建一个音频文件,但在音频文件中,我想控制每个文件的音量级别。

我该怎么办?

ffmpeg -i video.mp4 -i input1.mp3 -i input2.mp3
-filter_complex "[1]volume=0.5,pan=2c[a];[2]volume=0.7,pan=2c[b];[a][b]amix=duration=shortest"
-ac 2 -c:a libmp3lame -q:v 0 output.mp4

我就是这样做的。首先使用以下方法合并输入的音频文件。

private fun mergeAudios() {
//ffmpeg -i one.mp3 -i two.mp3 -shortest -filter_complex 
//"[0:a]adelay=10000|10000,volume=0.4[a0]; 
// [1:a]volume=5.0[a1]; 
// [a0][a1]amix=inputs=2[out]" 
// -map "[out]" -ac 2 -c:a libfdk_aac output.m4a
val finalAudio =
File(Environment.getExternalStorageDirectory().absolutePath + "/" + System.currentTimeMillis() + ".mp3")
val command = arrayOf(
"-i",
Environment.getExternalStorageDirectory().absolutePath + "/2.mp3",
"-i",
Environment.getExternalStorageDirectory().absolutePath + "/1543575307959.mp3",
"-shortest",
"-filter_complex",
"[0:a]volume=0.4[a0];[1:a]volume=5.0[a1];[a0][a1]amix=inputs=2:duration=shortest",
finalAudio.absolutePath
)
Log.d("ffmpeg", command.contentDeepToString())
ffmpeg.execute(command, object : ExecuteBinaryResponseHandler() {
override fun onFinish() {
super.onFinish()
}
override fun onSuccess(message: String?) {
super.onSuccess(message)
Log.d("ffmpeg", "onSuccess ")
}
override fun onFailure(message: String?) {
super.onFailure(message)
Log.d("ffmpeg", "failure " + message)
}
override fun onProgress(message: String?) {
super.onProgress(message)
Log.d("ffmpeg", "progress " + message)
}
override fun onStart() {
super.onStart()
}
})
}

然后将合并后的音频文件与视频文件合并。

private fun mergeAudioVideo() {
val finalVideo =
File(Environment.getExternalStorageDirectory().absolutePath + "/" + System.currentTimeMillis() + ".mp4")
//ffmpeg -i video.mp4 -i audio.wav 
//-c:v copy -c:a aac -strict experimental 
//-map 0:v:0 -map 1:a:0 output.mp4
val command = arrayOf(
"-i",
Environment.getExternalStorageDirectory().absolutePath + "/2.mp4",
"-i",
Environment.getExternalStorageDirectory().absolutePath + "/1543577399776.mp3"
,
"-c:v",
"copy",
"-c:a",
"aac",
"-strict",
"experimental",
"-map",
"0:v:0",
"-map",
"1:a:0",
finalVideo.absolutePath
)
ffmpeg.execute(command, object : ExecuteBinaryResponseHandler() {
override fun onFinish() {
super.onFinish()
}
override fun onSuccess(message: String?) {
super.onSuccess(message)
Log.d("ffmpeg", "onSuccess ")
}
override fun onFailure(message: String?) {
super.onFailure(message)
Log.d("ffmpeg", "failure " + message)
}
override fun onProgress(message: String?) {
super.onProgress(message)
Log.d("ffmpeg", "progress " + message)
}
override fun onStart() {
super.onStart()
}
})

}

如果它对你有用,试试这个。您可能需要一些额外的标志,因为您的视频没有音频文件。如果方法中的命令不适用,请尝试删除音频标志的-map参数

对于单个命令,这可能会起作用。我现在没有完整的项目来测试它,所以不能确认这个。

fun mergeAudioVideoDirectly(){
val finalVideo =
File(Environment.getExternalStorageDirectory().absolutePath + "/" + System.currentTimeMillis() + ".mp4")
//ffmpeg -i <input1> -i <input2> -filter_complex "[0:a:0][1:a:0]amix[outa]" -map "[0:v:0]" -map ["outa"] <output>
val command = arrayOf(
"-i",
Environment.getExternalStorageDirectory().absolutePath + "/2.mp4",
"-i",
Environment.getExternalStorageDirectory().absolutePath + "/1.mp3",
"-filter_complex",
"[0:a:0][1:a:0]amix[outa]",
"-map",
"0:v:0",
"-map",
"[outa]",
finalVideo.absolutePath
)
Log.d("ffmpeg ","command "+command.contentDeepToString())
ffmpeg.execute(command, object : ExecuteBinaryResponseHandler() {
override fun onFinish() {
super.onFinish()
}
override fun onSuccess(message: String?) {
super.onSuccess(message)
Log.d("ffmpeg", "onSuccess ")
}
override fun onFailure(message: String?) {
super.onFailure(message)
Log.d("ffmpeg", "failure " + message)
}
override fun onProgress(message: String?) {
super.onProgress(message)
}
override fun onStart() {
super.onStart()
}
})
}

请尝试以下命令混合音频视频和音量设置

fun videoMixWithAudio(isNeedAudioCropped: Boolean): Array<String?> {
val cmdList = ArrayList<String>()
var cmds: Array<String?>? = null
try {
cmdList.add("-y")
cmdList.add("-ss")
cmdList.add(startVideoDuration.toString())
cmdList.add("-t")
cmdList.add(endVideoDuration.toString())
cmdList.add("-i")
cmdList.add(videoPath)
cmdList.add("-ss")
if (!isNeedAudioCropped) {
cmdList.add("0")
} else {
cmdList.add(startAudioDuration.toString())
}
cmdList.add("-t")
cmdList.add(endVideoDuration.toString())
cmdList.add("-stream_loop")
cmdList.add("-1")
cmdList.add("-i")
cmdList.add(audioPath)
if (videovolume == -1f && audiovolume > -1) {
cmdList.add("-c:v")
if (startVideoDuration > 0) {
cmdList.add("mpeg4")
cmdList.add("-b:v")
cmdList.add("2304000")
} else {
cmdList.add("copy")
}
cmdList.add("-c:a")
cmdList.add("aac")
cmdList.add("-map")
cmdList.add("1:a:0")
cmdList.add("-map")
cmdList.add("0:v:0")
cmdList.add("-strict")
cmdList.add("-2")
if (audiovolume < 0.99 || audiovolume > 1.01) {
cmdList.add("-vol")
cmdList.add((audiovolume * 100).toInt().toString())
}
}else{
cmdList.add("-c:v")
if (startVideoDuration > 0) {
cmdList.add("mpeg4")
cmdList.add("-b:v")
cmdList.add("2304000")
} else {
cmdList.add("copy")
}
cmdList.add("-map")
cmdList.add("0:v:0")
cmdList.add("-strict")
cmdList.add("-2")
cmdList.add("-filter_complex")
cmdList.add(
String.format(
"[0:a]aformat=sample_fmts=fltp:sample_rates=48000:channel_layouts=stereo,volume=%f[a0];" +
"[1:a]aformat=sample_fmts=fltp:sample_rates=48000:channel_layouts=stereo,volume=%f[a1];" +
"[a0][a1]amix=inputs=2:duration=first[aout]",
videovolume,
audiovolume
)
)
cmdList.add("-map")
cmdList.add("[aout]")
}
cmdList.add("-b:a")
cmdList.add("128000")
cmdList.add("-ac")
cmdList.add("2")
cmdList.add("-ar")
cmdList.add("44100")
cmdList.add("-movflags")
cmdList.add("faststart")
cmdList.add("-preset")
cmdList.add("ultrafast")
cmdList.add(outputpath)
cmds = arrayOfNulls<String>(cmdList.size)
cmdList.toArray(cmds)
} catch (e: java.lang.Exception) {
e.printStackTrace()
}
return cmds!!
}

相关内容

最新更新