import android.media.MediaCodec;
import android.media.MediaCodecInfo;
import android.media.MediaFormat;
import android.util.Log;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
/**
* pcm轉AAC編碼
* Created by gj on 2017/4/7.
*/
public class AacEncode {
private MediaCodec mediaCodec;
private String mediaType = "OMX.google.aac.encoder";
//解碼后保存文件
private File file;
ByteBuffer[] inputBuffers = null;
ByteBuffer[] outputBuffers = null;
MediaCodec.BufferInfo bufferInfo;
FileOutputStream encFi = null;
//pts時間基數
long presentationTimeUs = 0;
//創建一個輸出流用來輸出轉換的數據
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
public AacEncode() {
}
//設置輸出路徑
public void setOutputPath(String outPath){
File file = new File(outPath);
try {
encFi = new FileOutputStream(file);
}catch (IOException e){
e.printStackTrace();
}
}
public void start(){
try {
mediaCodec = MediaCodec.createEncoderByType(MediaFormat.MIMETYPE_AUDIO_AAC);
//mediaCodec = MediaCodec.createByCodecName(mediaType);
} catch (IOException e) {
e.printStackTrace();
}
// 設置音頻采樣率,44100是目前的標准,但是某些設備仍然支持22050,16000,11025
final int kSampleRates[] = {8000, 11025, 22050, 44100, 48000};
//比特率 聲音中的比特率是指將模擬聲音信號轉換成數字聲音信號后,單位時間內的二進制數據量,是間接衡量音頻質量的一個指標
final int kBitRates[] = {64000, 96000, 128000};
//初始化 此格式使用的音頻編碼技術、音頻采樣率、使用此格式的音頻信道數(單聲道為 1,立體聲為 2)
MediaFormat mediaFormat = MediaFormat.createAudioFormat(
MediaFormat.MIMETYPE_AUDIO_AAC, kSampleRates[3], 2);
mediaFormat.setString(MediaFormat.KEY_MIME, MediaFormat.MIMETYPE_AUDIO_AAC);
mediaFormat.setInteger(MediaFormat.KEY_AAC_PROFILE,MediaCodecInfo.CodecProfileLevel.AACObjectLC);
//比特率 聲音中的比特率是指將模擬聲音信號轉換成數字聲音信號后,單位時間內的二進制數據量,是間接衡量音頻質量的一個指標
mediaFormat.setInteger(MediaFormat.KEY_BIT_RATE, kBitRates[1]);
//傳入的數據大小
mediaFormat.setInteger(MediaFormat.KEY_MAX_INPUT_SIZE, 4096);// It will
//設置相關參數
mediaCodec.configure(mediaFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
//開始
mediaCodec.start();
inputBuffers = mediaCodec.getInputBuffers();
outputBuffers = mediaCodec.getOutputBuffers();
bufferInfo = new MediaCodec.BufferInfo();
}
/**
* 關閉釋放資源
*
* @author:gj
* @date: 2017/4/25
* @time: 16:19
**/
public void close() {
try {
mediaCodec.stop();
mediaCodec.release();
outputStream.flush();
outputStream.close();
encFi.close();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 開始編碼
* offset 偏移量
* size 數據大小
**/
public void encode(byte[] input, int offset, int size) throws Exception {
int inputBufferIndex = mediaCodec.dequeueInputBuffer(-1);//其中需要注意的有dequeueInputBuffer(-1),參數表示需要得到的毫秒數,-1表示一直等,0表示不需要等,傳0的話程序不會等待,但是有可能會丟幀。
if (inputBufferIndex >= 0) {
ByteBuffer inputBuffer = inputBuffers[inputBufferIndex];
inputBuffer.clear();
inputBuffer.put(input);
inputBuffer.limit(input.length);
//計算pts
long pts = computePresentationTime(presentationTimeUs);
mediaCodec.queueInputBuffer(inputBufferIndex, offset, size, pts, 0);
presentationTimeUs += 1;
}
int outputBufferIndex = mediaCodec.dequeueOutputBuffer(bufferInfo, 0);
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);
//添加ADTS頭
byte[] outData = new byte[outPacketSize];
addADTStoPacket(outData, outPacketSize);
outputBuffer.get(outData, 7, outBitsSize);
outputBuffer.position(bufferInfo.offset);
//寫到輸出流里
outputStream.write(outData);
// Log.e("AudioEncoder", outData.length + " bytes written");
mediaCodec.releaseOutputBuffer(outputBufferIndex, false);
outputBufferIndex = mediaCodec.dequeueOutputBuffer(bufferInfo, 0);
}
//輸出流的數據轉成byte[]
byte[] out = outputStream.toByteArray();
encFi.write(out);
//寫完以后重置輸出流,否則數據會重復
outputStream.flush();
outputStream.reset();
}
/**
* 給編碼出的aac裸流添加adts頭字段
*
* @param packet 要空出前7個字節,否則會搞亂數據
* @param packetLen
*/
private void addADTStoPacket(byte[] packet, int packetLen) {
int profile = 2; //AAC LC
int freqIdx = 4; //44.1KHz
int chanCfg = 2; //CPE
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;
}
//計算PTS,實際上這個pts對應音頻來說作用並不大,設置成0也是沒有問題的
private long computePresentationTime(long frameIndex) {
return frameIndex * 90000 * 1024 / 44100;
}
}
//調用
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class PcmAac extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_pcm_aac);
AacEncode aacEncode = new AacEncode();
aacEncode.start();
aacEncode.setOutputPath("/data/local/tmp/yi.aac");
int size = 4096;
byte[] inBuffer = new byte[size];
File inFile = new File("/data/local/tmp/yi.pcm");
FileInputStream in = null;
int len = 0;
try {
in = new FileInputStream(inFile);
while ((len = in.read(inBuffer, 0, 2048)) > 0){
aacEncode.encode(inBuffer, 1024, len);
}
aacEncode.close();
}catch (IOException e){
e.printStackTrace();
}catch (java.lang.Exception e){
e.printStackTrace();
}
}
}