import android.content.Context;
import android.media.MediaCodec;
import android.media.MediaCodecInfo;
import android.media.MediaFormat;
import android.os.SystemClock;
import android.util.Log;
import androidx.annotation.NonNull;
import com.r3ci.hdmiplayer.mediarender.AudioPlayer;
import com.r3ci.hdmiplayer.utils.DateUtils;
import com.r3ci.recordlib.VideoFactory;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
public class AACEncode2 {
private final String TAG = AACEncode2.class.getSimpleName();
private CodecThread mCodecThread = null;
protected boolean mStreaming = false;
private MediaCodec mMediaCodec = null;
private int mChannelCount = 2;
private int mBitsPerSample = 16;
private int mBitrate = 64000;
private int mSamperrate = 48000;
private BlockingQueue<RawData> mQueue = new ArrayBlockingQueue(100);
private Context mContext = null;
private VideoFactory mFileMuxer = null;
public AACEncode2(Context context, VideoFactory mMuxer, int bitrate, int samplerrate, int channel) {
mContext = context;
mFileMuxer = mMuxer;
mBitrate = bitrate;
mSamperrate = samplerrate;
mChannelCount = channel;
//createTestFile();
}
class CodecThread extends Thread {
CodecThread(@NonNull String name) {
super(name);
}
@Override
public void run() {
super.run();
while (mStreaming) {
try {
readOutputData();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
private void readOutputData() throws IOException {
RawData au = mQueue.poll();
if(au == null)
return;
int index = mMediaCodec.dequeueInputBuffer(-1);
if (index >= 0) {
final ByteBuffer buffer = mMediaCodec.getInputBuffer(index);
buffer.clear();
buffer.put(au.buf);
if (au.length > 0) {
mMediaCodec.queueInputBuffer(index, 0, au.length, au.timeStamp, 0);
}
}
//queueInputBuffer一次,dequeueOutputBuffer可能需要几次
MediaCodec.BufferInfo mInfo = new MediaCodec.BufferInfo();
int outIndex;
do {
outIndex = mMediaCodec.dequeueOutputBuffer(mInfo, 100);
if (outIndex >= 0) {
ByteBuffer buffer = mMediaCodec.getOutputBuffer(outIndex);
if (mInfo.size != 0) {
if (buffer == null) {
throw new RuntimeException("encodecOutputBuffer" + outIndex + "was null");
}
if(mFileMuxer != null) {
int totalLen = mInfo.size+7;
byte[] outStream = new byte[totalLen];
addADTStoPacket(outStream, totalLen, 2);
buffer.get(outStream, 7, mInfo.size);
//saveTestFile(outStream);
mFileMuxer.writeData(1, outStream, totalLen, mInfo.presentationTimeUs, 1);
}
}
mMediaCodec.releaseOutputBuffer(outIndex, false);
}
} while (outIndex >= 0);
}
public void addADTStoPacket(byte[] packet, int packetLen, int chancfg) {
int profile = 2; //AAC LC,MediaCodecInfo.CodecProfileLevel.AACObjectLC;
int freqIdx = 3; //见后面注释avpriv_mpeg4audio_sample_rates中48000对应的数组下标,来自ffmpeg源码
int chanCfg = chancfg; //见后面注释channel_configuration
/*int avpriv_mpeg4audio_sample_rates[] = {96000, 88200, 64000, 48000, 44100, 32000,24000, 22050, 16000, 12000, 11025, 8000, 7350};
channel_configuration: 表示声道数chanCfg
0: Defined in AOT Specifc Config
1: 1 channel: front-center
2: 2 channels: front-left, front-right
3: 3 channels: front-center, front-left, front-right
4: 4 channels: front-center, front-left, front-right, back-center
5: 5 channels: front-center, front-left, front-right, back-left, back-right
6: 6 channels: front-center, front-left, front-right, back-left, back-right, LFE-channel
7: 8 channels: front-center, front-left, front-right, side-left, side-right, back-left, back-right, LFE-channel
8-15: Reserved
*/
// fill in ADTS data
packet[0] = (byte)0xFF;
packet[1] = (byte)0xF1;
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;
}
static class RawData {
byte[] buf;
int length;
long timeStamp;
RawData(byte[] data, int size, long pts) {
length = size;
buf = new byte[size];
System.arraycopy(data, 0, buf, 0, length);
timeStamp = pts;
}
}
public void startCodec() {
Log.d(TAG, "startCodec: ");
int periodInFrames = 1024;
int mBufferSize = periodInFrames * mBitsPerSample * mChannelCount / 8;
MediaFormat format = new MediaFormat();
format.setString(MediaFormat.KEY_MIME, MediaFormat.MIMETYPE_AUDIO_AAC);
format.setInteger(MediaFormat.KEY_BIT_RATE, mBitrate);
format.setInteger(MediaFormat.KEY_CHANNEL_COUNT, mChannelCount);
format.setInteger(MediaFormat.KEY_SAMPLE_RATE, mSamperrate);
format.setInteger(MediaFormat.KEY_AAC_PROFILE, MediaCodecInfo.CodecProfileLevel.AACObjectLC);
//format.setInteger(MediaFormat.KEY_MAX_INPUT_SIZE, mBufferSize);
try {
mMediaCodec = MediaCodec.createEncoderByType(MediaFormat.MIMETYPE_AUDIO_AAC);
} catch (IOException e) {
throw new RuntimeException(e);
}
mMediaCodec.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
mMediaCodec.start();
mStreaming = true;
if (mCodecThread == null) {
mCodecThread = new CodecThread("AudioEncode");
mCodecThread.start();
}
Log.d(TAG, "startCodec: finish" );
}
public void stop() {
mStreaming = false;
try {
Thread t1 = mCodecThread;
mCodecThread = null;
if (t1 != null) {
t1.interrupt();
t1.join();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
if(mMediaCodec != null)
{
mMediaCodec.stop();
mMediaCodec.release();
mMediaCodec=null;
}
mQueue.clear();
}
public void addData(byte[] data, int size, long pts) {
mQueue.offer(new RawData(data, size, pts));
}
private String sendFileVideo = "";
public void createTestFile(){
try {
String file = mContext.getExternalCacheDir() + "/" + "testAudio.aac";
sendFileVideo = file;
File videofile = new File(sendFileVideo);
if (videofile.exists()) {
videofile.delete();
}
videofile.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
}
public void saveTestFile(byte[] buffer){
FileOutputStream out = null;
try {
String testfile = sendFileVideo;
out = new FileOutputStream(testfile,true);
if(buffer.length > 0)
{
out.write(buffer);
}
out.flush();
} catch (IOException e) {
e.printStackTrace();
}finally {
if(out != null){
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
Android 音频编码,含adts头
于 2024-05-17 18:52:36 首次发布