2017-10-22 17 views
1

44100Hz 모노 64kbit AAC-LC 사운드를 pcm raw로 디코딩합니다. 그렇게하면 AudioTrack으로 pcm raw를 재생할 수 있습니다.AudioTrack에 디코딩 된 AAC 사운드 이상한 사운드

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(); 
    } 
    } 
} 

로그 캣은 말한다 : 여기

는 클래스

 
    2048 bytes decoded 

그리고 난 시간에 이상한 소리 시간을 얻었다. 디코딩은 괜찮아 보인다. 버퍼 크기에서 내 의견 이슈. 그러나 나는 무엇을 해야할지 모른다! 모든 것이 좋은 것처럼 보입니다.

나는 buffersize audiotrack 및 들어오는 데이터를 변경하려고했지만 변경하지 않았습니다.

아이디어가 있으십니까?

답변

-1

Decode 메서드를 호출하기 전에 디코더 구성을 설정하지 않은 것 같습니다.

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

아래의 순서대로 스레드에서 디코드 및 재생을 수행해야합니다. 디코딩()은 디코딩 방식과 동일합니다.

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(); 
     }