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
}
}