
MediaCodec.jpg
MediaCodec 的整體流程如上圖所示,從input 輸入數(shù)據(jù),從output 輸出數(shù)據(jù),編碼的時候輸入的是原始數(shù)據(jù),輸出的是編碼后的數(shù)據(jù)。
初始化
configure 編碼器的時候要將flag 設(shè)置為encode。
public void startEncode(MediaFormat format) {
mFormat = format;
final String mimeType = format.getString(MediaFormat.KEY_MIME);
// Check to see if this is actually a video mime type. If it is, then create
// a codec that can decode this mime type.
try {
mCodec = MediaCodec.createEncoderByType(mimeType);
} catch (IOException e) {
throw new RuntimeException(e);
}
mCodec.configure(format,null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
mCodec.start();
}
寫數(shù)據(jù)
將原始數(shù)據(jù)送給 MediaCodec。
public void sendFrame(byte[] input, long pts, int flags) {
int size = input.length;
int inputBufferId = mCodec.dequeueInputBuffer(timeOut);
if (inputBufferId >= 0) {
// fill inputBuffers[inputBufferId] with valid data
ByteBuffer buffer = mCodec.getInputBuffer(inputBufferId);
buffer.put(input);
mCodec.queueInputBuffer(inputBufferId, 0, size, pts, flags);
}
}
取數(shù)據(jù)
從 MediaCodec 中取出編碼后的數(shù)據(jù),這里要注意返回的outputBufferId,會有不同的處理。
public VEAVPacket receivePacket() {
VEAVPacket packet = new VEAVPacket();
int outputBufferId = mCodec.dequeueOutputBuffer(mBufferInfo, timeOut);
if (outputBufferId == MediaCodec.INFO_TRY_AGAIN_LATER) {
Log.d(TAG, "INFO_TRY_AGAIN_LATER");
return packet;
} else if (outputBufferId == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
// Subsequent data will conform to new format.
packet.format = mCodec.getOutputFormat();
return packet;
} else if (outputBufferId < 0) {
Log.d(TAG, "receivePacket:" + outputBufferId);
return packet;
}
// outputBuffers[outputBufferId] is ready to be processed or rendered.
ByteBuffer outputBuffer = mCodec.getOutputBuffer(outputBufferId);
if (outputBuffer == null) {
return packet;
}
byte[] outData = new byte[mBufferInfo.size];
outputBuffer.get(outData);
packet.buffer = ByteBuffer.wrap(outData);
packet.bufferInfo = mBufferInfo;
mCodec.releaseOutputBuffer(outputBufferId, timeOut);
return packet;
}
結(jié)束
public void stopEncode() {
mCodec.stop();
mCodec.release();
}
注意事項(xiàng)
封裝的時候可能提前需要獲取 sps 和 pps,然而編碼器接收到一定數(shù)據(jù)才會吐出這些信息,因此,我們可以先送入一些空數(shù)據(jù),將這個信息給擠出來。
public MediaFormat getOutputFormat() {
if (mOutFormat != null) {
return mOutFormat;
}
byte [] data = new byte[1];
long time = System.currentTimeMillis();
sendFrame(data, time, 0);
VEAVPacket videoPacket = receivePacket();
if (videoPacket.format != null) {
mOutFormat = videoPacket.format;
}
return mOutFormat;
}