微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

在Android上使用AudioRecord和MediaCodec对AAC Audio进行编码

我试图使用 android AudioRecord和MediaCodec来编码aac音频.我创建了一个非常类似于( Encoding H.264 from camera with Android MediaCodec)的编码器类.使用这个类,我创建了一个AudioRecord的实例,并告诉它将其byte []数据读取到AudioEncoder(audioEncoder.offerEncoder(Data)).
while(isRecording) 
 {
  audioRecord.read(Data,Data.length);
  audioEncoder.offerEncoder(Data);
 }

这是我的AudioRecord设置

int audioSource = MediaRecorder.AudioSource.MIC;
    int sampleRateInHz = 44100;
    int channelConfig = AudioFormat.CHANNEL_IN_MONO;
    int audioFormat = AudioFormat.ENCODING_PCM_16BIT;
    int bufferSizeInBytes = AudioRecord.getMinBufferSize(sampleRateInHz,channelConfig,audioFormat);

我成功收集了一些byte []数组数据并将其写入本地文件.不幸的是,该文件不可播放.我在网上进行了一些搜索,并发现了一个相关的帖子(How to generate the AAC ADTS elementary stream with Android MediaCodec).所以有同样问题的人说主要的问题是“MediaCodec编码器生成原始的AAC流,原始的AAC流需要被转换成可播放的格式,如ADTS流”.所以我试图添加ADTS标题.然而,在添加了ADTS标题(我在下面的代码中注释掉)后,我的AudioEncoder甚至不会写输出音频文件.
有什么我错过的吗?我的设置是否正确?

欢迎任何建议,意见和意见,非常感谢.多谢你们!

import android.media.MediaCodec;
import android.media.MediaCodecInfo;
import android.media.MediaFormat;
import android.os.Environment;
import android.util.Log;

import java.io.bufferedoutputstream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;

public class AudioEncoder {

    private MediaCodec mediaCodec;
    private bufferedoutputstream outputStream;
    private String mediaType = "audio/mp4a-latm";

    public AudioEncoder() {
        File f = new File(Environment.getExternalStorageDirectory(),"Download/audio_encoded.aac");
        touch(f);
        try {
            outputStream = new bufferedoutputstream(new FileOutputStream(f));
            Log.e("AudioEncoder","outputStream initialized");
        } catch (Exception e){
            e.printstacktrace();
        }

        mediaCodec = MediaCodec.createEncoderByType(mediaType);
        final int kSampleRates[] = { 8000,11025,22050,44100,48000 };
        final int kBitRates[] = { 64000,128000 };
        MediaFormat mediaFormat  = MediaFormat.createAudioFormat(mediaType,kSampleRates[3],1);
        mediaFormat.setInteger(MediaFormat.KEY_AAC_PROFILE,MediaCodecInfo.CodecProfileLevel.AACObjectLC);

        mediaFormat.setInteger(MediaFormat.KEY_BIT_RATE,kBitRates[1]);
        mediaCodec.configure(mediaFormat,null,MediaCodec.CONfigURE_FLAG_ENCODE);
        mediaCodec.start();
    }

    public void close() {
        try {
            mediaCodec.stop();
            mediaCodec.release();
            outputStream.flush();
            outputStream.close();
        } catch (Exception e){
            e.printstacktrace();
        }
    }

    // called AudioRecord's read
    public synchronized void offerEncoder(byte[] input) {
        Log.e("AudioEncoder",input.length + " is coming");

        try {
            ByteBuffer[] inputBuffers = mediaCodec.getInputBuffers();
            ByteBuffer[] outputBuffers = mediaCodec.getoutputBuffers();
            int inputBufferIndex = mediaCodec.dequeueInputBuffer(-1);
            if (inputBufferIndex >= 0) {
                ByteBuffer inputBuffer = inputBuffers[inputBufferIndex];
                inputBuffer.clear();

                inputBuffer.put(input);


                mediaCodec.queueInputBuffer(inputBufferIndex,input.length,0);
            }

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

////trying to add a ADTS
//            while (outputBufferIndex >= 0) {
//                int outBitsSize   = bufferInfo.size;
//                int outPacketSize = outBitsSize + 7;    // 7 is ADTS size
//                ByteBuffer outputBuffer = outputBuffers[outputBufferIndex];
//
//                outputBuffer.position(bufferInfo.offset);
//                outputBuffer.limit(bufferInfo.offset + outBitsSize);
//
//                byte[] outData = new byte[outPacketSize];
//                addADTStoPacket(outData,outPacketSize);
//
//                outputBuffer.get(outData,7,outBitsSize);
//                outputBuffer.position(bufferInfo.offset);
//
////                byte[] outData = new byte[bufferInfo.size];
//                outputStream.write(outData,outData.length);
//                Log.e("AudioEncoder",outData.length + " bytes written");
//
//                mediaCodec.releaSEOutputBuffer(outputBufferIndex,false);
//                outputBufferIndex = mediaCodec.dequeueOutputBuffer(bufferInfo,0);
//
//            }


//Without ADTS header
            while (outputBufferIndex >= 0) {
                ByteBuffer outputBuffer = outputBuffers[outputBufferIndex];
                byte[] outData = new byte[bufferInfo.size];
                outputBuffer.get(outData);
                outputStream.write(outData,outData.length);
                Log.e("AudioEncoder",outData.length + " bytes written");

                mediaCodec.releaSEOutputBuffer(outputBufferIndex,false);
                outputBufferIndex = mediaCodec.dequeueOutputBuffer(bufferInfo,0);

            }
        } catch (Throwable t) {
            t.printstacktrace();
        }

    }

    /**
     *  Add ADTS header at the beginning of each and every AAC packet.
     *  This is needed as MediaCodec encoder generates a packet of raw
     *  AAC data.
     *
     *  Note the packetLen must count in the ADTS header itself.
     **/
    private void addADTStoPacket(byte[] packet,int packetLen) {
        int profile = 2;  //AAC LC
        //39=MediaCodecInfo.CodecProfileLevel.AACObjectELD;
        int freqIdx = 4;  //44.1KHz
        int chanCfg = 2;  //CPE

        // fill in ADTS data
        packet[0] = (byte)0xFF;
        packet[1] = (byte)0xF9;
        packet[2] = (byte)(((profile-1)<<6) + (freqIdx<<2) +(chanCfg>>2));
        packet[3] = (byte)(((chanCfg&3)<<6) + (packetLen>>11));
        packet[4] = (byte)((packetLen&0x7FF) >> 3);
        packet[5] = (byte)(((packetLen&7)<<5) + 0x1F);
        packet[6] = (byte)0xFC;
    }

    public void touch(File f)
    {
        try {
            if(!f.exists())
                f.createNewFile();
        } catch (IOException e) {
            e.printstacktrace();
        }
    }
}

解决方法

您可以使用Android的 MediaMuxer将MediaCodec创建的原始流打包成.mp4文件.奖金:包含在.mp4中的AAC数据包不需要ADTS头.

我有一个working example of this technique on Github.

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Android 通过adb shell命令查看内存,CPU,启动时间,电量等信息 by:授客 QQ:1033553122 1、 查看内存信息 1)查看所有内存信息 命令: dumpsys meminfo 例: C:\Users\laiyu&gt;adb shell shell@android:/ $
Monkey Android app稳定性测试工具之Monkey使用教程 by:授客 QQ:1033553122 由于篇幅问题,仅提供百度网盘下载链接: Android app稳定性测试工具之Monkey使用教程.pdf
Android 常见adb命令 by:授客 QQ:1033553122 1、 查看所有已链接的设备 命令: adb devices 例: C:\Users\laiyu&gt;adb devices List of devices attached 5d3b5aac device 设备命令 2、 复制
这篇“android轻量级无侵入式管理数据库自动升级组件怎么实现”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定...
今天小编给大家分享一下Android实现自定义圆形进度条的常用方法有哪些的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文...
这篇文章主要讲解了“Android如何解决字符对齐问题”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Android...
这篇文章主要介绍“Android岛屿数量算法怎么使用”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“Android岛屿数量算...
本篇内容主要讲解“Android如何开发MQTT协议的模型及通信”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Andro...
本文小编为大家详细介绍“Android数据压缩的方法是什么”,内容详细,步骤清晰,细节处理妥当,希望这篇“Android数据压缩的方法是什么”文章能帮助大家解决疑惑...
这篇“Android怎么使用Intent传大数据”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅...