天天看點

Exoplayer使用記錄4-調節音軌中某個頻道的聲音

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

繼續閱讀