Exoplayer使用記錄4-調節音軌中某個頻道的聲音
By Xdestiny. 2018/2/5
概述
又是個奇葩需求…有個7.1音軌,想要具體調節其中某個頻道的聲音。
解決思路
還是上Issue上搜吧…果然有人問過同樣的問題
Implement volume controlling AudioProcessor, with independent control of channel volumes
具體來說就是要寫一個用于修改單通道聲音
audioprocessor
。需要注意的是,在調用自定義的processor前,exoplayer會先調用一個重采樣processor以及一個映射processor。是以自定義處理的均是處理bit16的音頻
此外還遇到了個奇怪的問題。由于測試時最後還是通過立體聲的形式放出來,同樣的代碼對于立體聲,AAC4.0工作正常,但對于5.1, 7.1就有問題。為此我還提了一個Issue給ExoPlayer。後來發現,再寫一個混音器放在後面就OK。當然,如果後面接的直接就是5.1或者7.1的播放裝置就得去掉這個混音器了。
具體代碼
class MyAudioProcessor: AudioProcessor {
private val TAG = "MyAudioProcessor"
private var m_channelCnt = Format.NO_VALUE
private var m_sampleRate = Format.NO_VALUE
private var m_encoding = C.ENCODING_INVALID
private var m_inputEnd = false
private var m_buffer: ByteBuffer = EMPTY_BUFFER
private var m_outputBuffer: ByteBuffer = EMPTY_BUFFER
private var volume: Array<Float> = Array(8, { _ -> 1.0f}) // 控制具體每個頻道的音量大小
fun SetVolume(idx: Int, vol: Float){
if(idx >= volume.size)
throw IllegalArgumentException()
volume[idx] = vol
}
fun GetVolume(idx: Int): Float{
if(idx >= volume.size)
throw IllegalArgumentException()
return volume[idx]
}
override fun isActive(): Boolean {
return m_encoding != C.ENCODING_INVALID
}
override fun queueEndOfStream() {
m_inputEnd = true
}
override fun configure(sampleRateHz: Int, channelCount: Int, encoding: Int): Boolean {
Log.d(TAG, "channel cnt = $channelCount")
m_channelCnt = channelCount
m_sampleRate = sampleRateHz
m_encoding = encoding
return true
}
override fun getOutputEncoding(): Int {
return m_encoding
}
override fun flush() {
m_outputBuffer = EMPTY_BUFFER
m_inputEnd = false
}
override fun queueInput(buffer: ByteBuffer) {
//最後隻輸出立體聲混音結果
var position = buffer.position()
val limit = buffer.limit()
val size = limit - position
if (m_buffer.capacity() < size)
m_buffer = ByteBuffer.allocateDirect(size).order(ByteOrder.nativeOrder())
else
m_buffer.clear()
when(m_encoding){
C.ENCODING_PCM_16BIT->{
while(position < limit){
var retL = 0.0f
var retR = 0.0f
for(i in 0..m_channelCnt - 1){
if(i%2 == 0)
retL += buffer.getShort(position + i * 2) * volume[i]
else
retR += buffer.getShort(position + i * 2) * volume[i]
}
position += m_channelCnt * 2
m_buffer.putShort((retL / m_channelCnt).toShort())
m_buffer.putShort((retR / m_channelCnt).toShort())
}
}
else->{
throw IllegalStateException()
}
}
buffer.position(limit)
m_buffer.flip()
m_outputBuffer = m_buffer
}
override fun isEnded(): Boolean {
return m_inputEnd && m_outputBuffer === AudioProcessor.EMPTY_BUFFER
}
override fun getOutput(): ByteBuffer {
val outputBuffer = m_outputBuffer
m_outputBuffer = EMPTY_BUFFER
return outputBuffer
}
override fun reset() {
flush()
m_buffer = AudioProcessor.EMPTY_BUFFER
m_sampleRate = Format.NO_VALUE
m_channelCnt = Format.NO_VALUE
m_encoding = C.ENCODING_INVALID
}
override fun getOutputChannelCount(): Int {
//最後隻輸出立體聲混音結果
return 2
}
}