如何在Android上编写音频文件,最好是.3gp

时间:2012-10-27 00:32:39

标签: android audio audio-recording

我已经研究了很长一段时间了,但仍然没有快乐。

我知道MediaRecorder会读取一个音频源并直接写入一个文件,采用多种格式之一。而且我也知道AudioRecord会读取音频源并让你处理原始数据,但有没有办法从你的应用程序写入数据?

例如,我想读取音频,以一种简单的方式过滤它,然后写入.3gp文件。有没有办法做到这一点?在搜索示例时,我只能通过手动编写标题来找到生成.wav文件的方法。

3 个答案:

答案 0 :(得分:1)

使用JNI编写您自己的编码器或使用现有的编码器,例如FFMpeg

这个问题也很有用 FFmpeg on Android

答案 1 :(得分:0)

答案 2 :(得分:0)

.aac会为你效力吗?如果是,那么检查一下: 使用manager类使用新的Thread运行此runnable。在startRecording按钮上单击:

  1. 初始化新主题。
  2. 使用.aac扩展名创建文件。
  3. 创建文件输出流。
  4. 设置输出
  5. SetListener并执行线程。
  6. OnStopClick:

    1. 中断线程,音频将保存在文件中。
    2. Here is full gist of for reference :

      import android.media.AudioFormat;
      import android.media.AudioRecord;
      import android.media.MediaCodec;
      import android.media.MediaCodecInfo;
      import android.media.MediaFormat;
      import android.media.MediaRecorder;
      import android.os.Build;
      import android.util.Log;
      
      import java.io.IOException;
      import java.io.OutputStream;
      import java.nio.ByteBuffer;
      
      public class AudioRecordThread implements Runnable {
      
          private static final String TAG = AudioRecordThread.class.getSimpleName();
      
          private static final int SAMPLE_RATE = 44100;
          private static final int SAMPLE_RATE_INDEX = 4;
          private static final int CHANNELS = 1;
          private static final int BIT_RATE = 32000;
      
          private final int bufferSize;
          private final MediaCodec mediaCodec;
          private final AudioRecord audioRecord;
          private final OutputStream outputStream;
      
          private OnRecorderFailedListener onRecorderFailedListener;
      
      
          AudioRecordThread(OutputStream outputStream, OnRecorderFailedListener onRecorderFailedListener) throws IOException {
      
              this.bufferSize = AudioRecord.getMinBufferSize(SAMPLE_RATE, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT);
              this.audioRecord = createAudioRecord(this.bufferSize);
              this.mediaCodec = createMediaCodec(this.bufferSize);
              this.outputStream = outputStream;
              this.onRecorderFailedListener = onRecorderFailedListener;
      
              this.mediaCodec.start();
      
              try {
                  audioRecord.startRecording();
              } catch (Exception e) {
                  Log.w(TAG, e);
                  mediaCodec.release();
                  throw new IOException(e);
              }
          }
      
          @Override
          public void run() {
              if (onRecorderFailedListener != null) {
                  Log.d(TAG, "onRecorderStarted");
                  onRecorderFailedListener.onRecorderStarted();
              }
              MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
              ByteBuffer[] codecInputBuffers = mediaCodec.getInputBuffers();
              ByteBuffer[] codecOutputBuffers = mediaCodec.getOutputBuffers();
      
              try {
                  while (!Thread.interrupted()) {
      
                      boolean success = handleCodecInput(audioRecord, mediaCodec, codecInputBuffers, Thread.currentThread().isAlive());
                      if (success)
                          handleCodecOutput(mediaCodec, codecOutputBuffers, bufferInfo, outputStream);
                  }
              } catch (IOException e) {
                  Log.w(TAG, e);
              } finally {
                  mediaCodec.stop();
                  audioRecord.stop();
      
                  mediaCodec.release();
                  audioRecord.release();
      
                  try {
                      outputStream.close();
                  } catch (IOException e) {
                      e.printStackTrace();
                  }
              }
          }
      
      
          private boolean handleCodecInput(AudioRecord audioRecord,
                                           MediaCodec mediaCodec, ByteBuffer[] codecInputBuffers,
                                           boolean running) throws IOException {
              byte[] audioRecordData = new byte[bufferSize];
              int length = audioRecord.read(audioRecordData, 0, audioRecordData.length);
      
              if (length == AudioRecord.ERROR_BAD_VALUE ||
                      length == AudioRecord.ERROR_INVALID_OPERATION ||
                      length != bufferSize) {
      
                  if (length != bufferSize) {
                      if (onRecorderFailedListener != null) {
                          Log.d(TAG, "length != BufferSize calling onRecordFailed");
                          onRecorderFailedListener.onRecorderFailed();
                      }
                      return false;
                  }
              }
      
              int codecInputBufferIndex = mediaCodec.dequeueInputBuffer(10 * 1000);
      
              if (codecInputBufferIndex >= 0) {
                  ByteBuffer codecBuffer = codecInputBuffers[codecInputBufferIndex];
                  codecBuffer.clear();
                  codecBuffer.put(audioRecordData);
                  mediaCodec.queueInputBuffer(codecInputBufferIndex, 0, length, 0, running ? 0 : MediaCodec.BUFFER_FLAG_END_OF_STREAM);
              }
      
              return true;
          }
      
          private void handleCodecOutput(MediaCodec mediaCodec,
                                         ByteBuffer[] codecOutputBuffers,
                                         MediaCodec.BufferInfo bufferInfo,
                                         OutputStream outputStream)
                  throws IOException {
              int codecOutputBufferIndex = mediaCodec.dequeueOutputBuffer(bufferInfo, 0);
      
              while (codecOutputBufferIndex != MediaCodec.INFO_TRY_AGAIN_LATER) {
                  if (codecOutputBufferIndex >= 0) {
                      ByteBuffer encoderOutputBuffer = codecOutputBuffers[codecOutputBufferIndex];
      
                      encoderOutputBuffer.position(bufferInfo.offset);
                      encoderOutputBuffer.limit(bufferInfo.offset + bufferInfo.size);
      
                      if ((bufferInfo.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) != MediaCodec.BUFFER_FLAG_CODEC_CONFIG) {
                          byte[] header = createAdtsHeader(bufferInfo.size - bufferInfo.offset);
      
      
                          outputStream.write(header);
      
                          byte[] data = new byte[encoderOutputBuffer.remaining()];
                          encoderOutputBuffer.get(data);
                          outputStream.write(data);
                      }
      
                      encoderOutputBuffer.clear();
      
                      mediaCodec.releaseOutputBuffer(codecOutputBufferIndex, false);
                  } else if (codecOutputBufferIndex == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {
                      codecOutputBuffers = mediaCodec.getOutputBuffers();
                  }
      
                  codecOutputBufferIndex = mediaCodec.dequeueOutputBuffer(bufferInfo, 0);
              }
          }
      
      
          private byte[] createAdtsHeader(int length) {
              int frameLength = length + 7;
              byte[] adtsHeader = new byte[7];
      
              adtsHeader[0] = (byte) 0xFF; // Sync Word
              adtsHeader[1] = (byte) 0xF1; // MPEG-4, Layer (0), No CRC
              adtsHeader[2] = (byte) ((MediaCodecInfo.CodecProfileLevel.AACObjectLC - 1) << 6);
              adtsHeader[2] |= (((byte) SAMPLE_RATE_INDEX) << 2);
              adtsHeader[2] |= (((byte) CHANNELS) >> 2);
              adtsHeader[3] = (byte) (((CHANNELS & 3) << 6) | ((frameLength >> 11) & 0x03));
              adtsHeader[4] = (byte) ((frameLength >> 3) & 0xFF);
              adtsHeader[5] = (byte) (((frameLength & 0x07) << 5) | 0x1f);
              adtsHeader[6] = (byte) 0xFC;
      
              return adtsHeader;
          }
      
          private AudioRecord createAudioRecord(int bufferSize) {
              AudioRecord audioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC, SAMPLE_RATE,
                      AudioFormat.CHANNEL_IN_MONO,
                      AudioFormat.ENCODING_PCM_16BIT, bufferSize * 10);
      
              if (audioRecord.getState() != AudioRecord.STATE_INITIALIZED) {
                  Log.d(TAG, "Unable to initialize AudioRecord");
                  throw new RuntimeException("Unable to initialize AudioRecord");
              }
      
              if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
                  if (android.media.audiofx.NoiseSuppressor.isAvailable()) {
                      android.media.audiofx.NoiseSuppressor noiseSuppressor = android.media.audiofx.NoiseSuppressor
                              .create(audioRecord.getAudioSessionId());
                      if (noiseSuppressor != null) {
                          noiseSuppressor.setEnabled(true);
                      }
                  }
              }
      
      
              if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
                  if (android.media.audiofx.AutomaticGainControl.isAvailable()) {
                      android.media.audiofx.AutomaticGainControl automaticGainControl = android.media.audiofx.AutomaticGainControl
                              .create(audioRecord.getAudioSessionId());
                      if (automaticGainControl != null) {
                          automaticGainControl.setEnabled(true);
                      }
                  }
              }
      
      
              return audioRecord;
          }
      
          private MediaCodec createMediaCodec(int bufferSize) throws IOException {
              MediaCodec mediaCodec = MediaCodec.createEncoderByType("audio/mp4a-latm");
              MediaFormat mediaFormat = new MediaFormat();
      
              mediaFormat.setString(MediaFormat.KEY_MIME, "audio/mp4a-latm");
              mediaFormat.setInteger(MediaFormat.KEY_SAMPLE_RATE, SAMPLE_RATE);
              mediaFormat.setInteger(MediaFormat.KEY_CHANNEL_COUNT, CHANNELS);
              mediaFormat.setInteger(MediaFormat.KEY_MAX_INPUT_SIZE, bufferSize);
              mediaFormat.setInteger(MediaFormat.KEY_BIT_RATE, BIT_RATE);
              mediaFormat.setInteger(MediaFormat.KEY_AAC_PROFILE, MediaCodecInfo.CodecProfileLevel.AACObjectLC);
      
              try {
                  mediaCodec.configure(mediaFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
              } catch (Exception e) {
                  Log.w(TAG, e);
                  mediaCodec.release();
                  throw new IOException(e);
              }
      
              return mediaCodec;
          }
      
          interface OnRecorderFailedListener {
              void onRecorderFailed();
      
              void onRecorderStarted();
          }
      }