1.添加依赖
精简版:不包含MP3编码器
implementation 'com.arthenica:mobile-ffmpeg-min-gpl:4.4.LTS'
完整版:包含MP3编码
implementation 'com.arthenica:mobile-ffmpeg-full:4.4.LTS'
2.参考代码
import android.content.Context
import android.util.Log
import com.arthenica.mobileffmpeg.Config
import com.arthenica.mobileffmpeg.FFmpeg
import java.io.File
object AudioMerger {
private const val TAG = "AudioMerger"
fun testConvertToWav(context: Context) {
Log.i(TAG, "testConvertToWav")
val dir = context.getExternalFilesDir("")!!.absolutePath
val inputFile0 = File("$dir/audio_ai.wav")
val inputFile1 = File("$dir/audio_wav.wav")
val inputFile2 = File("$dir/audio_mp3.mp3")
val inputFile3 = File("$dir/video_mp4.mp4")
val outputFile0 = File("$dir/audio_ai_output.wav")
val outputFile1 = File("$dir/audio_wav_output.wav")
val outputFile2 = File("$dir/audio_mp3_output.wav")
val outputFile3 = File("$dir/video_mp4_output.wav")
convertToWav(inputFile0, outputFile0) { success, message ->
Log.i(TAG, "testConvertToWav, success: $success, message: $message")
}
}
fun testConcatWav(context: Context) {
Log.i(TAG, "testConcatWav")
val dir = context.getExternalFilesDir("")!!.absolutePath
val inputFile0 = File("$dir/audio_ai_output.wav")
val inputFile1 = File("$dir/audio_wav_output.wav")
val inputFile2 = File("$dir/audio_mp3_output.wav")
val inputFile3 = File("$dir/video_mp4_output.wav")
val outputFile1 = File("$dir/audio_wav_output_concat.wav")
val outputFile2 = File("$dir/audio_mp3_output_concat.wav")
val outputFile3 = File("$dir/video_mp4_output_concat.wav")
concatWav(inputFile0, inputFile3, outputFile3) { success, message ->
Log.i(TAG, "testConcatWav, success: $success, message: $message")
}
}
fun testConvertToMp3(context: Context) {
Log.i(TAG, "testConvertToMp3")
val dir = context.getExternalFilesDir("")!!.absolutePath
val inputFile1 = File("$dir/audio_wav_output_concat.wav")
val inputFile2 = File("$dir/audio_mp3_output_concat.wav")
val inputFile3 = File("$dir/video_mp4_output_concat.wav")
val outputFile1 = File("$dir/audio_wav_output_concat.mp3")
val outputFile2 = File("$dir/audio_mp3_output_concat.mp3")
val outputFile3 = File("$dir/video_mp4_output_concat.mp3")
convertToMp3(inputFile3, outputFile3) { success, message ->
Log.i(TAG, "testConvertToMp3, success: $success, message: $message")
}
}
fun convertToWav(
inputFile: File,
outputFile: File,
callback: (success: Boolean, message: String) -> Unit
) {
try {
// 检查输入文件
if (!inputFile.exists()) {
callback(false, "输入文件不存在")
return
}
// 构建FFmpeg命令
val convertCmd = arrayOf(
"-y",
"-i", inputFile.absolutePath,
"-ar", "44100", // 设置采样率
"-ac", "2", // 设置声道数
"-sample_fmt", "s16", // 设置位深
"-f", "wav", // 设置WAV格式
outputFile.absolutePath
)
// 执行转换
val returnCode = FFmpeg.execute(convertCmd)
// 处理结果
if (returnCode == Config.RETURN_CODE_SUCCESS) {
callback(true, "转换成功")
} else {
val errorLog = Config.getLastCommandOutput()
callback(false, "转换失败: $errorLog")
}
} catch (e: Exception) {
callback(false, "转换失败: ${e.message}")
}
}
fun concatWav(
inputFile1: File,
inputFile2: File,
outputFile: File,
callback: (success: Boolean, message: String) -> Unit
) {
// 检查输入文件
if (!inputFile1.exists() || !inputFile2.exists()) {
callback(false, "输入文件不存在")
return
}
// 输入文件路径集合
val inputFiles = mutableListOf<String>().apply {
add(inputFile1.absolutePath)
add(inputFile2.absolutePath)
}
// 创建临时目录
val tempDir = File(inputFile1.parentFile, "temp_concat_wav")
if (!tempDir.exists()) {
tempDir.mkdirs()
}
try {
// 创建临时文件
val concatFile = File(tempDir, "temp_concat_wav_list.txt").apply {
createNewFile()
writeText(inputFiles.joinToString("\n") {
"file '${
it.replace(
"'",
"'\\''"
)
}'"
})
}
// 构建FFmpeg命令
val concatCmd = arrayOf(
"-y",
"-f", "concat",
"-safe", "0",
"-i", concatFile.absolutePath,
"-c", "copy", // 直接拷贝流,因为之前已经统一了参数
outputFile.absolutePath
)
// 执行拼接
val returnCode = FFmpeg.execute(concatCmd)
// 处理结果
if (returnCode == Config.RETURN_CODE_SUCCESS) {
callback(true, "拼接成功")
} else {
val errorLog = Config.getLastCommandOutput()
callback(false, "拼接失败: $errorLog")
}
} catch (e: Exception) {
callback(false, "拼接失败: ${e.message}")
} finally {
// 清理临时文件
tempDir.deleteRecursively()
}
}
fun convertToMp3(
inputFile: File,
outputFile: File,
callback: (success: Boolean, message: String) -> Unit
) {
try {
// 检查输入文件
if (!inputFile.exists()) {
callback(false, "输入文件不存在")
return
}
// 构建FFmpeg命令
val convertCmd = arrayOf(
"-y",
"-i", inputFile.absolutePath,
"-codec:a", "libmp3lame",
"-qscale:a", "2",
outputFile.absolutePath
)
// 执行转换
val returnCode = FFmpeg.execute(convertCmd)
// 处理结果
if (returnCode == Config.RETURN_CODE_SUCCESS) {
callback(true, "转换成功")
} else {
val errorLog = Config.getLastCommandOutput()
callback(false, "转换失败: $errorLog")
}
} catch (e: Exception) {
callback(false, "转换失败: ${e.message}")
}
}
}