MediaCodec.jpg
MediaCodec 的整體流程如上圖所示,從input 輸入數(shù)據(jù)猫胁,從output 輸出數(shù)據(jù)维咸。解碼的時候輸入的是壓縮數(shù)據(jù),輸出的是解碼后的原始數(shù)據(jù)狐肢。
初始化
如果傳入了 Surface添吗,那么解碼完的數(shù)據(jù)可以直接渲染到 Surface 上。
public void startDecode(MediaFormat format, SurfaceView surfaceView) {
Surface surface = surfaceView.getHolder().getSurface();
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.createDecoderByType(mimeType);
} catch (IOException e) {
throw new RuntimeException(e);
}
mCodec.configure(format,surface, null, 0);
mCodec.start();
}
寫數(shù)據(jù)
將壓縮的數(shù)據(jù)送入解碼器份名。
public void sendPackage(VEAVPacket packet) {
int size = packet.buffer.capacity();
int inputBufferId = mCodec.dequeueInputBuffer(timeOut);
if (inputBufferId >= 0) {
// fill inputBuffers[inputBufferId] with valid data
ByteBuffer buffer = mCodec.getInputBuffer(inputBufferId);
buffer.put(packet.buffer);
mCodec.queueInputBuffer(inputBufferId, 0, size, packet.dts, packet.flag);
}
}
取數(shù)據(jù)
如果不直接渲染到 Surface 上碟联,我們也可以把解壓后的數(shù)據(jù)取出來。
public VEAVFrame receiveFrame() {
VEAVFrame frame = new VEAVFrame();
int outputBufferId = mCodec.dequeueOutputBuffer(mBufferInfo, timeOut);
if (outputBufferId == MediaCodec.INFO_TRY_AGAIN_LATER) {
Log.d(TAG, "INFO_TRY_AGAIN_LATER");
return frame;
} else if (outputBufferId < 0) {
Log.d(TAG, "receiveFrame:" + outputBufferId);
return frame;
}
// outputBuffers[outputBufferId] is ready to be processed or rendered.
ByteBuffer outputBuffer = mCodec.getOutputBuffer(outputBufferId);
if (outputBuffer == null) {
return frame;
}
byte[] outData = new byte[mBufferInfo.size];
outputBuffer.get(outData);
frame.data = outData;
mCodec.releaseOutputBuffer(outputBufferId, timeOut);
return frame;
}
直接渲染到 Surface 上
releaseOutputBuffer 里面的 boolean 變量控制這一幀是否需要渲染僵腺。
public void renderToSurface() {
int outputBufferId = mCodec.dequeueOutputBuffer(mBufferInfo, timeOut);
if (outputBufferId < 0) {
return;
}
mCodec.releaseOutputBuffer(outputBufferId, true);
}
結(jié)束
public void stopDecode() {
mCodec.stop();
mCodec.release();
}
注意事項
renderToSurface 的頻率需要外部控制鲤孵,不然會一下子全部渲染完了。