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

如何在Android上编写音频文件,最好是.3gp,android,audio,audio-recording,Android,Audio,Audio Recording,我研究这个已经有一段时间了,但仍然没有乐趣 我知道MediaRecorder将以几种格式之一读取音频源并直接写入文件。我也知道AudioRecord会读取音频源并让你处理原始数据,但是有没有办法从你的应用程序中写入数据 例如,我想读取音频,以某种简单的方式对其进行过滤,然后写入.3gp文件。有没有办法做到这一点?搜索示例时,我只能找到一种通过手动写入头来生成.wav文件的方法。编写自己的编码器或使用现有的编码器,如using JNI 这个问题也可能有用。 您查看了MediaCodec类了吗 .a

我研究这个已经有一段时间了,但仍然没有乐趣

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


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

编写自己的编码器或使用现有的编码器,如using JNI

这个问题也可能有用。

您查看了MediaCodec类了吗


.aac
对你有用吗?如果是,请检查以下内容: 使用管理器类以新线程运行此runnable。在开始录制按钮上,单击:

  • 初始化新线程
  • 创建扩展名为
    .aac
    的文件
  • 创建文件的输出流
  • 设定输出
  • 设置侦听器并执行线程
  • 点击桌面:

  • 中断线程,音频将保存在文件中
  • 导入android.media.AudioFormat;
    导入android.media.AudioRecord;
    导入android.media.MediaCodec;
    导入android.media.mediacodeinfo;
    导入android.media.MediaFormat;
    导入android.media.MediaRecorder;
    导入android.os.Build;
    导入android.util.Log;
    导入java.io.IOException;
    导入java.io.OutputStream;
    导入java.nio.ByteBuffer;
    公共类AudioRecordThread实现可运行{
    私有静态最终字符串标记=AudioRecordThread.class.getSimpleName();
    私有静态最终整数抽样率=44100;
    私有静态最终整数抽样率指数=4;
    专用静态最终整数通道=1;
    专用静态最终整数比特率=32000;
    私有最终整数缓冲大小;
    专用最终MediaCodec MediaCodec;
    私人最终录音;
    私有最终输出流OutputStream;
    私有OnRecorderFailedListener OnRecorderFailedListener;
    AudioRecordThread(OutputStream OutputStream,OnRecorderFailedListener OnRecorderFailedListener)抛出IOException{
    this.bufferSize=AudioRecord.getMinBufferSize(采样率,单声道中的AudioFormat.CHANNEL,AudioFormat.ENCODING,PCM,16位);
    this.audioRecord=createAudioRecord(this.bufferSize);
    this.mediaCodec=createMediaCodec(this.bufferSize);
    this.outputStream=outputStream;
    this.onRecorderFailedListener=onRecorderFailedListener;
    this.mediaCodec.start();
    试一试{
    录音。开始录制();
    }捕获(例外e){
    Log.w(TAG,e);
    mediaCodec.release();
    抛出新的IOException(e);
    }
    }
    @凌驾
    公开募捐{
    if(onRecorderFailedListener!=null){
    Log.d(标签“onRecorderStarted”);
    onRecorderFailedListener.onRecorderStarted();
    }
    MediaCodec.BufferInfo BufferInfo=新的MediaCodec.BufferInfo();
    ByteBuffer[]CodeInputBuffers=mediaCodec.getInputBuffers();
    ByteBuffer[]codecOutputBuffers=mediaCodec.getOutputBuffers();
    试一试{
    而(!Thread.interrupted()){
    boolean success=handleCodecInput(音频录制、mediaCodec、CodeInputBuffers、Thread.currentThread().isAlive());
    如果(成功)
    handleCodecOutput(mediaCodec、CodeOutputBuffers、bufferInfo、outputStream);
    }
    }捕获(IOE异常){
    Log.w(TAG,e);
    }最后{
    mediaCodec.stop();
    录音。停止();
    mediaCodec.release();
    audioRecord.release();
    试一试{
    outputStream.close();
    }捕获(IOE异常){
    e、 printStackTrace();
    }
    }
    }
    专用布尔HandleCodeInput(录音、录音、,
    MediaCodec MediaCodec,ByteBuffer[]CodeInputBuffers,
    布尔运行)抛出IOException{
    byte[]audioRecordData=新字节[bufferSize];
    int length=audioRecord.read(audioRecordData,0,audioRecordData.length);
    if(length==AudioRecord.ERROR\u BAD\u值||
    长度==AudioRecord.ERROR\u无效\u操作||
    长度!=缓冲区大小){
    如果(长度!=缓冲区大小){
    if(onRecorderFailedListener!=null){
    Log.d(标记“length!=BufferSize调用onRecordFailed”);
    onRecorderFailedListener.onRecorderFailed();
    }
    返回false;
    }
    }
    int codecInputBufferIndex=mediaCodec.dequeueInputBuffer(10*1000);
    如果(CodeInputBufferIndex>=0){
    ByteBuffer codecBuffer=codecInputBuffers[codecInputBufferIndex];
    codecBuffer.clear();
    codecBuffer.put(audioRecordData);
    mediaCodec.queueInputBuffer(CodeInputBufferIndex,0,长度,0,正在运行?0:mediaCodec.BUFFER\u标志\u流的结束\u);
    }
    返回true;
    }
    私有无效handleCodecOutput(MediaCodec MediaCodec,
    ByteBuffer[]编码输出缓冲区,
    MediaCodec.BufferInfo BufferInfo,
    OutputStream(输出流)
    抛出IOException{
    int codecOutputBufferIndex=mediaCodec.dequeueOutputBuffer(bufferInfo,0);
    while(codecOutputBufferIndex!=MediaCodec.INFO\u请稍后重试){
    如果(codecOutputBufferIndex>=0){
    ByteBuffer encoderOutputBuffer=codecOutputBuffers[codecOutputBufferIndex];
    编码Buffer.position(bufferInfo.offset);
    encoderOutputBuffer.limit(bufferInfo.offset+bufferInfo
    
    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();
        }
    }