我试图使用
android AudioRecord和MediaCodec来编码aac音频.我创建了一个非常类似于(
Encoding H.264 from camera with Android MediaCodec)的编码器类.使用这个类,我创建了一个AudioRecord的实例,并告诉它将其byte []数据读取到AudioEncoder(audioEncoder.offerEncoder(Data)).
这是我的AudioRecord设置
我成功收集了一些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头.