簡體   English   中英

Android MediaCodec AAC編碼器

[英]Android MediaCodec AAC encoder

I use the MediaCodec class provided by the Android SDK since API level 16 with the OMX.SEC.aac.enc encoder to encode audio to a file. 我從AudioRecord獲得音頻輸入。 我的AudioRecord實例配置如下:

bufferSize = AudioRecord.getMinBufferSize(44100, AudioFormat.CHANNEL_IN_STEREO, AudioFormat.ENCODING_PCM_16BIT);
recorder = new AudioRecord(MediaRecorder.AudioSource.MIC, 44100, AudioFormat.CHANNEL_IN_STEREO, AudioFormat.ENCODING_DEFAULT, bufferSize);

我能夠從AudioRecord實例播放原始數據,因此問題不存在。

我將 output 從AudioRecord實例寫入ByteBuffer實例,並將其從編碼器傳遞到可用的輸入緩沖區。 來自編碼器的 output 被寫入 SD 卡上的文件。

這些是我的MediaCodec實例的配置參數:

codec = MediaCodec.createEncoderByType("audio/mp4a-latm");
MediaFormat format = new MediaFormat();
format.setString(MediaFormat.KEY_MIME, "audio/mp4a-latm");
format.setInteger(MediaFormat.KEY_BIT_RATE, 64 * 1024);
format.setInteger(MediaFormat.KEY_CHANNEL_COUNT, 2);
format.setInteger(MediaFormat.KEY_SAMPLE_RATE, 44100);
format.setInteger(MediaFormat.KEY_AAC_PROFILE, MediaCodecInfo.CodecProfileLevel.AACObjectHE);
codec.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);

VLC 告訴我我的 aac 文件中沒有流。 命令FFMPEG -i @filename@給我以下錯誤: Invalid data found when processing input 我測試的所有媒體播放器都無法播放我的文件。

為什么我無法播放我的文件? 我在LogCat中沒有收到任何OpenMAX錯誤,並且應用程序在編碼時不會崩潰。 我寫了一個基於相同原理工作的視頻編碼器,它可以工作。

這是從AudioRecord實例讀取數據到緩沖區的代碼:

    new Thread() {
        public void run() {
            ByteBuffer byteBuffer = ByteBuffer.allocateDirect(bufferSize);
            int read = 0;
            while (isRecording) {
                read = recorder.read(byteBuffer, bufferSize);
                if(AudioRecord.ERROR_INVALID_OPERATION != read){
                    encoder.add(byteBuffer);
                }
            }
            recorder.stop();
        }
    }.start();

從我的編碼器添加的 function 將一個緩沖區的內容復制到另一個緩沖區:

public void add(ByteBuffer input) {
    if (!isRunning)
        return; 

    if (tmpInputBuffer == null)
        tmpInputBuffer = ByteBuffer.allocate(input.capacity());

    if (!tmpBufferClear)
        Log.e("audio encoder", "deadline missed"); //TODO lower bit rate

    synchronized (tmpInputBuffer) {
        tmpInputBuffer.clear();
        tmpInputBuffer.put(input);
        tmpInputBuffer.notifyAll();
        Log.d("audio encoder", "pushed data into tmpInputBuffer");
    }
}

以下代碼用於占用編碼器的輸入緩沖區:

new Thread() {
    public void run() {
        while (isRunning) {
            if (tmpInputBuffer == null)
                continue;
            synchronized (tmpInputBuffer) {
                if (tmpBufferClear) {
                    try {
                        Log.d("audio encoder", "falling asleep");
                        tmpInputBuffer.wait(); //wait when no input is available
                    } 
                    catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }

                ByteBuffer[] inputBuffers = codec.getInputBuffers();
                int inputBufferIndex;
                do
                    inputBufferIndex = codec.dequeueInputBuffer(-1);
                while (inputBufferIndex < 0);
                ByteBuffer inputBuffer = inputBuffers[inputBufferIndex];
                inputBuffer.clear();
                Log.d("input buffer size", String.valueOf(inputBuffer.capacity()));
                Log.d("tmp input buffer size", String.valueOf(tmpInputBuffer.capacity()));
                inputBuffer.put(tmpInputBuffer.array());
                tmpInputBuffer.clear();
                codec.queueInputBuffer(inputBufferIndex, 0, tmpInputBuffer.capacity(), 0, 0);
                tmpBufferClear = true;
                Log.d("audio encoder", "added to input buffer");
            }
        }
    }
}.start();

我將 output 從編碼器寫入本地文件,如下所示:

    new Thread() {
        public void run() {
            while (isRunning) {
                ByteBuffer[] outputBuffers = codec.getOutputBuffers();
                MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
                int outputBufferIndex = codec.dequeueOutputBuffer(bufferInfo, -1);
                while (outputBufferIndex >= 0) {
                    ByteBuffer outputBuffer = outputBuffers[outputBufferIndex];
                    byte[] outData = new byte[bufferInfo.size];
                    outputBuffer.get(outData);

                    try {
                        fileWriter.write(outData, 0, outData.length);
                    } 
                    catch (IOException e) {
                        e.printStackTrace();
                    }
                    codec.releaseOutputBuffer(outputBufferIndex, false);
                    outputBufferIndex = codec.dequeueOutputBuffer(bufferInfo, 0);
                    Log.d("audio encoder", "removed from output buffer");
                }
            }
            codec.stop();

            try {
                fileWriter.close();
            } 
            catch (IOException e) {
                e.printStackTrace();
            }
        }
    }.start();
                tmpBufferClear = true;
                Log.d("audio encoder", "added to input buffer");
            }
        }
    }
}.start();

我猜你錯過了MediaMuxer課程。 例如,如果您想將從 MediaCodec 獲取的內容寫入文件,則需要它。

我也必須解決 is 用例。 這是可能的,但有一些棘手的事情要讓它發揮作用。 我已將我的概念驗證應用程序上傳到 GitHub。 它有一個如何做到這一點的工作示例。

https://github.com/dburckh/EncodeRawAudio

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM