Android视频直播 ------ 2、编码。

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;

}

}

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容