FFmpeg-音频转换及拼接

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}")
        }
    }
}
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容