Android視頻直播 ------ 2、編碼。

MediaCodec官網(wǎng)
https://developer.android.google.cn/reference/android/media/MediaCodec


1、創(chuàng)建MediaCodec,設(shè)置編碼信息。

2、開(kāi)始編碼,壓縮,ICallBackByte回調(diào)byte[]數(shù)據(jù)流,就當(dāng)作是一個(gè)工具類(lèi),傳入nv21數(shù)據(jù)流,回調(diào)avc數(shù)據(jù)流。

編碼就創(chuàng)建 MediaCodec.createEncoderByType(),
解碼就創(chuàng)建 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;

}

}

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容