MediaCodec官网
https://developer.android.google.cn/reference/android/media/MediaCodec
1、创建MediaCodec,设置编码信息。
2、开始编码,压缩,ICallBackByte回调byte[]数据流,就当作是一个工具类,传入nv21数据流,回调avc数据流。
编码就创建 MediaCodec.createEncoderByType(),
解码就创建 MediaCodec.createDecoderByType();
完整代码如下:
public class NV21ToAvcEncoder {
private final static String TAG ="MeidaCodec";
private final int TIMEOUT_USEC =12000;
private MediaCodec mediaCodec;
int m_width;
int m_height;
int m_framerate;
public ArrayBlockingQueuenv21Queue =new ArrayBlockingQueue<>(10);
public byte[]configbyte;
@SuppressLint("NewApi")
public NV21ToAvcEncoder(int width,int height,int framerate) {
m_width = width;
m_height = height;
m_framerate = framerate;
MediaFormat mediaFormat =MediaFormat.createVideoFormat("video/avc", width, height);
mediaFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT,MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420SemiPlanar);
mediaFormat.setInteger(MediaFormat.KEY_BIT_RATE, width * height *5);
mediaFormat.setInteger(MediaFormat.KEY_FRAME_RATE, framerate);
mediaFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL,1);
mediaFormat.setInteger(MediaFormat.KEY_REPEAT_PREVIOUS_FRAME_AFTER,10000);
mediaFormat.setInteger(MediaFormat.KEY_BITRATE_MODE,1);
mediaFormat.setInteger(MediaFormat.KEY_COMPLEXITY,0);
try {
mediaCodec =MediaCodec.createEncoderByType("video/avc");
}catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
mediaCodec.configure(mediaFormat,null,null,MediaCodec.CONFIGURE_FLAG_ENCODE);
mediaCodec.start();
}
@SuppressLint("NewApi")
private void stopEncoder() {
if(!isRuning){
return;
}
try {
mediaCodec.stop();
mediaCodec.release();
}catch (Exception e) {
e.printStackTrace();
}
isRuning =false;
}
// ByteBuffer[] inputBuffers;
// ByteBuffer[] outputBuffers;
public boolean isRuning =false;
public void stopThread() {
try {
stopEncoder();
}catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
nv21Queue.clear();
}
public void startEncoderThread() {
Thread encoderThread =new Thread(() -> {
isRuning =true;
byte[] input =null;
long pts =0;
long generateIndex =0;
while (isRuning) {
if (nv21Queue.size() >0) {
input =nv21Queue.poll();
byte[]yuv420sp =new byte[m_width *m_height *3 /2];
nv21ToYuv420(input,yuv420sp,m_width,m_height);
input =yuv420sp;
}
if (input !=null) {
try {
long startMs =System.currentTimeMillis();
ByteBuffer[]inputBuffers =mediaCodec.getInputBuffers();
ByteBuffer[]outputBuffers =mediaCodec.getOutputBuffers();
int inputBufferIndex =mediaCodec.dequeueInputBuffer(-1);
if (inputBufferIndex >=0) {
pts = computePresentationTime(generateIndex);
ByteBuffer inputBuffer =inputBuffers[inputBufferIndex];
inputBuffer.clear();
inputBuffer.put(input);
mediaCodec.queueInputBuffer(inputBufferIndex,0, input.length, pts,0);
generateIndex +=1;
}
MediaCodec.BufferInfo bufferInfo =new MediaCodec.BufferInfo();
int outputBufferIndex =mediaCodec.dequeueOutputBuffer(bufferInfo,TIMEOUT_USEC);
while (outputBufferIndex >=0) {
//Log.i("AvcEncoder", "Get H264 Buffer Success! flag = "+bufferInfo.flags+",pts = "+bufferInfo.presentationTimeUs+"");
ByteBuffer outputBuffer =outputBuffers[outputBufferIndex];
byte[]outData =new byte[bufferInfo.size];
outputBuffer.get(outData);
if (bufferInfo.flags ==2) {
configbyte =new byte[bufferInfo.size];
configbyte =outData;
if (iCallBack !=null){
iCallBack.onFrame(configbyte);
}
}else if (bufferInfo.flags ==1) {
byte[]keyframe =new byte[bufferInfo.size +configbyte.length];
System.arraycopy(configbyte,0,keyframe,0,configbyte.length);
System.arraycopy(outData,0,keyframe,configbyte.length,outData.length);
if (iCallBack !=null){
iCallBack.onFrame(keyframe);
}
// outputStream.write(keyframe, 0, keyframe.length);
}else {
if (iCallBack !=null){
iCallBack.onFrame(outData);
}
// outputStream.write(outData, 0, outData.length);
}
mediaCodec.releaseOutputBuffer(outputBufferIndex,false);
outputBufferIndex =mediaCodec.dequeueOutputBuffer(bufferInfo,TIMEOUT_USEC);
}
}catch (Throwable t) {
t.printStackTrace();
}
}else {
try {
Thread.sleep(500);
}catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
encoderThread.start();
}
private void nv21ToYuv420(byte[] nv21,byte[] yuv420,int width,int height) {
if (nv21 ==null || yuv420 ==null) {
return;
}
try {
int framesize = width * height;
int i =0, j =0;
System.arraycopy(nv21,0, yuv420,0,framesize);
for (i =0; i
yuv420[i] = nv21[i];
}
for (j =0; j
yuv420[framesize + j -1] = nv21[j +framesize];
}
for (j =0; j
yuv420[framesize + j] = nv21[j +framesize -1];
}
}catch (Exception e) {
e.printStackTrace();
}
}
/**
* Generates the presentation time for frame N, in microseconds.
*/
private long computePresentationTime(long frameIndex) {
return 132 + frameIndex *1000000 /m_framerate;
}
public interface ICallBackByte{
void onFrame(byte[] data);
}
private ICallBackByte iCallBack;
public void setCallBackByte(ICallBackByte c){
iCallBack = c;
}
}