将AAC声音解码为AudioTrack Weird Sound

时间:2017-10-22 15:51:23

标签: android audio mediacodec decoder audiotrack

我正在将44100Hz单声道64kbit AAC-LC声音解码为pcm raw。这样我就可以用AudioTrack播放pcm raw。

这是班级:

package com.sametaylak.cstudio.lib;

import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioTrack;
import android.media.MediaCodec;
import android.media.MediaCodecInfo;
import android.media.MediaFormat;
import android.util.Log;

import net.butterflytv.rtmp_client.RtmpClient;

import java.io.IOException;
import java.nio.ByteBuffer;

public class AudioDecoder extends Thread {
private MediaCodec decoder;
private RtmpClient client;
private AudioTrack track;

public boolean startDecoder() {
    try {
        int bufferSizePlayer = AudioTrack.getMinBufferSize(44100, AudioFormat.CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_16BIT);
        track = new AudioTrack(AudioManager.STREAM_MUSIC, 44100, AudioFormat.CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_16BIT, bufferSizePlayer, AudioTrack.MODE_STREAM);
        client = new RtmpClient();
        decoder = MediaCodec.createDecoderByType("audio/mp4a-latm");

        MediaFormat format = new MediaFormat();
        format.setString(MediaFormat.KEY_MIME, "audio/mp4a-latm");
        format.setInteger(MediaFormat.KEY_CHANNEL_COUNT, 1);
        format.setInteger(MediaFormat.KEY_SAMPLE_RATE, 44100);
        format.setInteger(MediaFormat.KEY_BIT_RATE, 64 * 1024);
        format.setInteger(MediaFormat.KEY_AAC_PROFILE, MediaCodecInfo.CodecProfileLevel.AACObjectLC);

        int profile = 2;
        int freqIdx = 4;
        int chanCfg = 1;
        ByteBuffer csd = ByteBuffer.allocate(2);
        csd.put(0, (byte) (profile << 3 | freqIdx >> 1));
        csd.put(1, (byte)((freqIdx & 0x01) << 7 | chanCfg << 3));
        format.setByteBuffer("csd-0", csd);

        decoder.configure(format, null, null, 0);
        client.open("rtmp://192.168.1.41/live/samet live=1", false);
        track.play();
        start();
        return true;
    } catch (IOException e) {
        e.printStackTrace();
    }
    return false;
}

@Override
public void run() {
    byte[] data;

    ByteBuffer[] inputBuffers;
    ByteBuffer[] outputBuffers;

    ByteBuffer inputBuffer;
    ByteBuffer outputBuffer;

    MediaCodec.BufferInfo bufferInfo;
    int inputBufferIndex;
    int outputBufferIndex;

    byte[] outData;

    decoder.start();

    try {
        for (;;) {
            data = new byte[1024];
            client.read(data, 0, data.length);

            inputBuffers = decoder.getInputBuffers();
            outputBuffers = decoder.getOutputBuffers();
            inputBufferIndex = decoder.dequeueInputBuffer(-1);

            if (inputBufferIndex >= 0) {
                inputBuffer = inputBuffers[inputBufferIndex];
                inputBuffer.clear();

                inputBuffer.put(data);

                decoder.queueInputBuffer(inputBufferIndex, 0, data.length, 0, 0);
            }

            bufferInfo = new MediaCodec.BufferInfo();
            outputBufferIndex = decoder.dequeueOutputBuffer(bufferInfo, 0);

            while (outputBufferIndex >= 0) {
                outputBuffer = outputBuffers[outputBufferIndex];

                outputBuffer.position(bufferInfo.offset);
                outputBuffer.limit(bufferInfo.offset + bufferInfo.size);

                outData = new byte[bufferInfo.size];
                outputBuffer.get(outData);

                Log.d("AudioDecoder", outData.length + " bytes decoded");
                track.write(outData, 0, outData.length);

                decoder.releaseOutputBuffer(outputBufferIndex, false);
                outputBufferIndex = decoder.dequeueOutputBuffer(bufferInfo, 0);
            }
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
  }
}

Logcat说:

    2048 bytes decoded

我的声音时间很奇怪。我认为解码似乎没问题。我的意见来自缓冲区大小。但我不知道该怎么办!一切似乎都很好。

我尝试更改buffersize audiotrack和传入数据,但没有更改。

有什么想法吗?

1 个答案:

答案 0 :(得分:-1)

我认为你在调用解码方法之前没有设置解码器配置。

public boolean prepare() {
            mBufferInfo = new MediaCodec.BufferInfo();
            //开始播放
            mPlayer = new AudioTrack(AudioManager.STREAM_MUSIC, KEY_SAMPLE_RATE, CHANNEL_OUT, AUDIO_FORMAT, BUFFFER_SIZE, AudioTrack.MODE_STREAM);
            mPlayer.play();
            try {
                mDecoder = MediaCodec.createDecoderByType(MIME_TYPE);
                MediaFormat format = new MediaFormat();
                //解码配置
                format.setString(MediaFormat.KEY_MIME, MIME_TYPE);
                format.setInteger(MediaFormat.KEY_CHANNEL_COUNT, KEY_CHANNEL_COUNT);
                format.setInteger(MediaFormat.KEY_SAMPLE_RATE, KEY_SAMPLE_RATE);
                format.setInteger(MediaFormat.KEY_BIT_RATE, KEY_BIT_RATE);
                format.setInteger(MediaFormat.KEY_IS_ADTS, 1);
                format.setInteger(MediaFormat.KEY_AAC_PROFILE, KEY_AAC_PROFILE);

                int profile = KEY_AAC_PROFILE;  //AAC LC
                int freqIdx = FREQ_IDX;  //44.1KHz
                int chanCfg = CHAN_CFG;  //CPE
                ByteBuffer csd = ByteBuffer.allocate(2);
                csd.put(0, (byte) (profile << 3 | freqIdx >> 1));
                csd.put(1, (byte)((freqIdx & 0x01) << 7 | chanCfg << 3));
                format.setByteBuffer("csd-0", csd);

                mDecoder.configure(format, null, null, 0);
            } catch (IOException e) {
                e.printStackTrace();
                return false;
            }
            if (mDecoder == null) {
                Log.e(TAG, "create mediaDecode failed");
                return false;
            }
            mDecoder.start();
            return true;
        }

解码和播放跟踪按顺序完成,如下所示.decode()与你的解码方法相同。

public void run() {
            super.run();
            if (!prepare()) {
                isRunning = false;
                Log.d(TAG, "音频解码器初始化失败");
            }
            if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
                inputBuffers = mDecoder.getInputBuffers();
                outputBuffers = mDecoder.getOutputBuffers();
            }
            while (isRunning) {
                decode();
            }
            release();
        }
相关问题