object AudioEditUtil {
private const val TAG = "AudioEditUtil"
/**
* 裁剪音频
* @param audio 音频信息
* @param cutStartTime 裁剪开始时间
* @param cutEndTime 裁剪结束时间
*/
fun cutAudio(audio: Audio?, cutStartTime: Float, cutEndTime: Float): Boolean {
MLog.d(
TAG,
"cutAudio: audio = $audio, cutStartTime = $cutStartTime, cutEndTime = $cutEndTime"
)
if (audio == null) {
return false
}
if (cutStartTime == 0f && cutEndTime == audio.duration / 1000f) {
return false
}
if (cutStartTime >= cutEndTime) {
return false
}
// WAV 文件路径、采样率、声道数、采样数
val srcWavePath = audio.path
val sampleRate = audio.sampleRate
val channels = audio.channel
val bitNum = audio.bitNum
// 输入流
var srcFis: RandomAccessFile? = null
var newFos: RandomAccessFile? = null
// 临时存储路径
val tempOutPath = "${srcWavePath.substring(0, srcWavePath.lastIndexOf("."))}${AudioConstant.SUFFIX_TEMP}"
MLog.d(
TAG,
"cutAudio: srcWavePath = $srcWavePath, sampleRate = $sampleRate, channels = $channels, bitNum = $bitNum, tempOutPath = $tempOutPath"
)
try {
// 创建输入流
srcFis = RandomAccessFile(srcWavePath, "rw")
newFos = RandomAccessFile(tempOutPath, "rw")
// 源文件开始读取位置,结束读取文件,读取数据的大小
val cutStartPos = getPositionFromWave(cutStartTime, sampleRate, channels, bitNum)
val cutEndPos = getPositionFromWave(cutEndTime, sampleRate, channels, bitNum)
val contentSize = cutEndPos - cutStartPos
MLog.d(
TAG,
"cutAudio: cutStartPos = $cutStartPos, cutEndPos = $cutEndPos, contentSize = $contentSize"
)
// 复制 wav head 字节数据
val headerData =
AudioEncodeUtil.getWaveHeader(contentSize.toLong(), sampleRate, channels, bitNum)
copyHeadData(headerData, newFos)
// 移动到文件开始读取处
srcFis.seek((AudioConstant.WAVE_HEAD_SIZE + cutStartPos).toLong())
// 复制裁剪的音频数据
copyData(srcFis, newFos, contentSize)
} catch (e: Exception) {
MLog.d(TAG, "cutAudio: error =$e")
e.printStackTrace()
return false
} finally {
// 关闭输入流
MLog.d(TAG, "cutAudio: 关闭流")
if (srcFis != null) {
try {
srcFis.close()
} catch (e: IOException) {
e.printStackTrace()
}
}
if (newFos != null) {
try {
newFos.close()
} catch (e: IOException) {
e.printStackTrace()
}
}
}
return true
}
/**
* 获取 WAVE 文件某个时间对应的数据位置
* @param time 时间
* @param sampleRate 采样率
* @param channels 声道数
* @param bitNum 采样位数
* @return
*/
private fun getPositionFromWave(time: Float, sampleRate: Int, channels: Int, bitNum: Int): Int {
MLog.d(
TAG,
"getPositionFromWave: time = $time, sampleRate = $sampleRate, channels = $channels, bitNum = $bitNum"
)
val byteNum = bitNum / 8
var position = (time * sampleRate * channels * byteNum).toInt()
position = position / (byteNum * channels) * (byteNum * channels)
return position
}
/**
* 复制wav header 数据
*
* @param headerData wav header 数据
* @param fos 目标输出流
*/
private fun copyHeadData(headerData: ByteArray, fos: RandomAccessFile) {
try {
fos.seek(0)
fos.write(headerData)
} catch (ex: Exception) {
ex.printStackTrace()
}
}
/**
* 复制数据
*
* @param fis 源输入流
* @param fos 目标输出流
* @param copySize 复制大小
*/
private fun copyData(fis: RandomAccessFile, fos: RandomAccessFile, copySize: Int) {
MLog.d(TAG, "copyData: copySize = $copySize")
var buffer = ByteArray(2048)
var length: Int
var totalReadLength = 0
try {
while (fis.read(buffer).also { length = it } != -1) {
MLog.d(TAG, "copyData: 写入数据 length = $length")
fos.write(buffer, 0, length)
totalReadLength += length
val remainSize = copySize - totalReadLength
if (remainSize <= 0) {
// 读取指定位置完成
MLog.d(TAG, "copyData: 读取指定位置完成")
break
} else if (remainSize < buffer.size) {
// 离指定位置的大小小于 buffer 的大小,换 remainSize 的 buffer
MLog.d(TAG, "copyData: 离指定位置的大小小于 buffer 的大小,换 remainSize 的 buffer")
buffer = ByteArray(remainSize)
}
}
} catch (e: Exception) {
MLog.d(TAG, "copyData: error = $e")
e.printStackTrace()
}
}
}
音频-剪辑
于 2023-03-15 21:27:32 首次发布