Android应用中如何将WAV音频文件转换为ByteBuffer以输入YAMNet TensorFlow Lite模型
Android应用中如何将WAV音频文件转换为ByteBuffer以输入YAMNet TensorFlow Lite模型
我来帮你搞定这个问题!要把WAV文件转换成YAMNet模型需要的ByteBuffer,核心是先把音频处理成模型要求的格式——16kHz采样率、单通道、32位浮点型PCM数据,而且必须是固定的15600个样本(对应0.975秒音频)。下面是具体的步骤和代码实现:
一、核心思路
YAMNet对输入有严格要求,所以我们需要先完成两个关键操作:
- 将原WAV文件转成16kHz单通道的浮点PCM数据;
- 把处理后的音频数据裁剪/补0到15600个样本,再转成符合要求的ByteBuffer。
二、完整代码实现
这里推荐用TarsosDSP库来简化音频格式转换(它是Android端处理音频重采样、格式转换的轻量工具),先在build.gradle里添加依赖:
implementation 'be.tarsos.dsp:TarsosDSP:2.4.0'
然后编写转换函数:
import android.os.Build import java.io.File import java.nio.ByteBuffer import java.nio.ByteOrder import be.tarsos.dsp.AudioEvent import be.tarsos.dsp.AudioProcessor import be.tarsos.dsp.io.android.AudioDispatcherFactory fun convertWavToYamnetInput(wavFile: File): ByteBuffer { // 1. 初始化音频调度器,直接把WAV文件转成16kHz单通道的浮点数据 // 参数:文件、目标采样率、单次读取样本数、偏移量 val dispatcher = AudioDispatcherFactory.fromFile(wavFile, 16000, 15600, 0) val floatSamples = mutableListOf<Float>() // 2. 读取并收集音频样本,直到凑够15600个 dispatcher.addAudioProcessor(object : AudioProcessor { override fun process(audioEvent: AudioEvent): Boolean { val buffer = audioEvent.floatBuffer floatSamples.addAll(buffer.toList()) // 样本数够了就停止读取 return floatSamples.size < 15600 } override fun processingFinished() {} }) dispatcher.run() // 3. 调整样本数到固定的15600:多了截断,少了补0 val fixedSamples = FloatArray(15600) if (floatSamples.size >= 15600) { floatSamples.take(15600).toFloatArray().copyInto(fixedSamples) } else { floatSamples.toFloatArray().copyInto(fixedSamples) } // 4. 将浮点数组转成TensorFlow Lite需要的ByteBuffer val byteBuffer = ByteBuffer.allocateDirect(fixedSamples.size * 4) // 每个float占4字节 byteBuffer.order(ByteOrder.nativeOrder()) // 对齐设备本地字节序 byteBuffer.asFloatBuffer().put(fixedSamples) byteBuffer.rewind() // 重置指针到缓冲区开头 return byteBuffer }
三、使用示例
把转换后的ByteBuffer传入模型即可:
// 假设你已经获取到WAV文件的File实例 val wavFile = File(getExternalFilesDir(null), "cough.wav") val byteBuffer = convertWavToYamnetInput(wavFile) // 加载到TensorBuffer中 val audioClip = TensorBuffer.createFixedSize(intArrayOf(15600), DataType.FLOAT32) audioClip.loadBuffer(byteBuffer) // 运行模型推理 val model = YamnetClassification.newInstance(this) val outputs = model.process(audioClip) val scores = outputs.scoresAsTensorBuffer // 处理结果:比如找到得分最高的类别(需要配合YAMNet的标签表映射) val scoresArray = scores.floatArray val topCategoryIndex = scoresArray.indices.maxByOrNull { scoresArray[it] } // 这里可以用官方提供的标签列表,把索引转成具体类别名称(比如"cough")
四、注意事项
- 权限问题:如果读取外部存储的WAV文件,Android 10及以上需要申请
READ_EXTERNAL_STORAGE权限,或者使用Scoped Storage访问文件; - 无第三方库方案:如果不想依赖TarsosDSP,可以用Android原生的
MediaCodec+AudioFormat手动解码和重采样,但代码会复杂很多; - 标签映射:YAMNet的得分数组索引对应官方的标签列表,你需要把索引和具体类别名称(比如"speech"、"cough")做映射,标签表可以从YAMNet的官方文档获取。
备注:内容来源于stack exchange,提问作者M. K.
相关产品推荐
相关产品推荐

