如何在FFmpeg命令中以ByteArray作为输入输出,避免文件存储延迟
如何用FFmpegKit直接处理ByteArray音频数据(无需文件存储)
核心思路
FFmpeg支持通过-指代标准输入(stdin)和标准输出(stdout),FFmpegKit提供了对应重载方法,可直接传入输入流、输出流替代文件路径,彻底避免磁盘IO带来的额外延迟。
步骤1:更新依赖
替换旧的mobile-ffmpeg依赖为最新版FFmpegKit:
implementation 'com.arthenica:ffmpeg-kit-android-full:5.1.0'
步骤2:修正音频处理函数
以下是完整的处理函数,直接基于ShortArray输入输出,无文件操作:
import com.arthenica.ffmpegkit.FFmpegKit import com.arthenica.ffmpegkit.FFmpegSession import com.arthenica.ffmpegkit.ReturnCode import java.io.ByteArrayInputStream import java.io.ByteArrayOutputStream import java.nio.ByteBuffer import java.nio.ByteOrder import android.util.Log fun processAudioAsChipmunk(audioData: ShortArray, sampleRate: Int, channelCount: Int): ShortArray { // 将ShortArray转为PCM 16位小端格式的ByteArray val inputBuffer = ByteBuffer.allocate(audioData.size * 2) inputBuffer.order(ByteOrder.nativeOrder()) inputBuffer.asShortBuffer().put(audioData) val inputByteArray = inputBuffer.array() val inputStream = ByteArrayInputStream(inputByteArray) val outputStream = ByteArrayOutputStream() // 构造FFmpeg命令:完全匹配输入音频参数,应用花栗鼠音效,输出PCM数据 val command = arrayOf( "-f", "s16le", // 输入格式:PCM 16位小端 "-ar", sampleRate.toString(), // 输入采样率,和AudioRecord一致 "-ac", channelCount.toString(), // 输入通道数,和AudioRecord一致 "-i", "-", // 从标准输入读取数据 "-af", "asetrate=${sampleRate * 2},aresample=${sampleRate},atempo=0.5", // 花栗鼠音效滤镜组合 "-f", "s16le", // 输出格式:PCM 16位小端 "-" // 输出到标准输出 ) // 执行异步命令,传入输入输出流和回调 val session: FFmpegSession = FFmpegKit.executeAsync( command, inputStream, outputStream, { session -> if (!ReturnCode.isSuccess(session.returnCode)) { Log.e("FFmpeg", "处理失败:${session.failStackTrace}") } } ) // 同步等待处理完成,避免返回空数据 session.wait() // 检查执行结果 if (!ReturnCode.isSuccess(session.returnCode)) { return ShortArray(0) } // 将输出ByteArray转回ShortArray val outputByteArray = outputStream.toByteArray() val outputBuffer = ByteBuffer.wrap(outputByteArray) .order(ByteOrder.nativeOrder()) .asShortBuffer() val outputShortArray = ShortArray(outputBuffer.remaining()) outputBuffer.get(outputShortArray) // 关闭流释放资源 inputStream.close() outputStream.close() return outputShortArray }
步骤3:整合到音频读写流程
在原有AudioRecord/AudioTrack逻辑中调用处理函数:
// 读取麦克风数据 val read = record!!.read(audioData, 0, minBuffer) if (read > 0) { // 仅处理实际读取到的音频片段 val processedAudioData = processAudioAsChipmunk( audioData.copyOfRange(0, read), record.sampleRate, record.channelCount ) // 播放处理后的音频 player!!.write(processedAudioData, 0, processedAudioData.size) }
关键注意事项
- 参数匹配:命令中的
-f、-ar、-ac必须和AudioRecord的配置完全一致,否则会出现音频失真、速度异常等问题。 - 滤镜替换:若需使用rubberband滤镜,直接替换
-af参数即可,例如"rubberband=pitch=1.5"。 - 流处理:FFmpegKit会自动完成输入流到FFmpeg的喂料,以及FFmpeg输出到输出流的写入,无需手动操作数据流。
- 同步等待:
session.wait()确保处理完成后再返回结果,避免异步执行导致的空数据问题。
内容的提问来源于stack exchange,提问作者Rohit gupta
相关产品推荐
相关产品推荐

