Android音视频开发只硬件解码组件MediaCodec讲解
什么是MediaCodec
MediaCodec是Android提供的一种硬件解码组件,通过MediaCodec可以将硬件解码器(比如硬解码器)的硬件加速模块进行利用以提高视频进行解码的速度。
相比于软解码,硬解码可以有效的提高解码速度,使得更多的设备可以进行高清视频的播放。
使用MediaCodec进行视频解码
使用MediaCodec进行视频解码需要涉及到以下几个步骤:
- 创建MediaFormat对象,并将需要进行解码的参数设置好。比如需要解码的视频的Mime类型、视频的分辨率、视频的码率等。
MediaFormat format = MediaFormat.createVideoFormat("video/avc", 1280, 720);
format.setInteger(MediaFormat.KEY_BIT_RATE, 10000000);
format.setInteger(MediaFormat.KEY_FRAME_RATE, 30);
- 创建并初始化一个MediaCodec对象。
MediaCodec codec = MediaCodec.createDecoderByType("video/avc");
codec.configure(format, null, null, 0);
codec.start();
- 将需要进行解码的视频数据传递给MediaCodec进行解码。
ByteBuffer[] inputBuffers = codec.getInputBuffers();
int inputBufferIndex = codec.dequeueInputBuffer(-1);
if (inputBufferIndex >= 0) {
ByteBuffer inputBuffer = inputBuffers[inputBufferIndex];
inputBuffer.clear();
inputBuffer.put(videoData);
codec.queueInputBuffer(inputBufferIndex, 0, videoData.length, 0, 0);
}
- 从MediaCodec中获取到解码后的数据并进行处理。
```
ByteBuffer[] outputBuffers = codec.getOutputBuffers();
MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
int outputBufferIndex = codec.dequeueOutputBuffer(bufferInfo, 0);
if (outputBufferIndex >= 0) {
ByteBuffer outputBuffer = outputBuffers[outputBufferIndex];
byte[] outputData = new byte[bufferInfo.size];
outputBuffer.get(outputData);
// 进行数据处理...
codec.releaseOutputBuffer(outputBufferIndex, false);
}
```
示例1:视频播放器
下面是一个简单的视频播放器,使用MediaCodec进行硬解码:
public class VideoPlayer {
private MediaCodec codec;
private Surface surface;
private boolean isPlaying;
public void startPlay(String filePath, Surface surface) throws IOException {
isPlaying = true;
this.surface = surface;
File file = new File(filePath);
FileInputStream inputStream = new FileInputStream(file);
int length = (int) file.length();
byte[] data = new byte[length];
inputStream.read(data);
inputStream.close();
MediaExtractor extractor = new MediaExtractor();
extractor.setDataSource(filePath);
int trackIndex = -1;
for (int i = 0; i < extractor.getTrackCount(); i++) {
MediaFormat format = extractor.getTrackFormat(i);
String mime = format.getString(MediaFormat.KEY_MIME);
if (mime.startsWith("video/")) {
extractor.selectTrack(i);
codec = MediaCodec.createDecoderByType(mime);
codec.configure(format, surface, null, 0);
break;
}
}
codec.start();
ByteBuffer[] inputBuffers = codec.getInputBuffers();
ByteBuffer[] outputBuffers = codec.getOutputBuffers();
MediaCodec.BufferInfo info = new MediaCodec.BufferInfo();
boolean isEOS = false;
long startMs = System.currentTimeMillis();
while (isPlaying) {
if (!isEOS) {
int inIndex = codec.dequeueInputBuffer(10000);
if (inIndex >= 0) {
ByteBuffer buffer = inputBuffers[inIndex];
int sampleSize = extractor.readSampleData(buffer, 0);
if (sampleSize < 0) {
codec.queueInputBuffer(inIndex, 0, 0, 0, MediaCodec.BUFFER_FLAG_END_OF_STREAM);
isEOS = true;
} else {
codec.queueInputBuffer(inIndex, 0, sampleSize, extractor.getSampleTime(), 0);
extractor.advance();
}
}
}
int outIndex = codec.dequeueOutputBuffer(info, 10000);
switch (outIndex) {
case MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED:
outputBuffers = codec.getOutputBuffers();
break;
case MediaCodec.INFO_OUTPUT_FORMAT_CHANGED:
break;
case MediaCodec.INFO_TRY_AGAIN_LATER:
break;
default:
ByteBuffer buffer = outputBuffers[outIndex];
codec.releaseOutputBuffer(outIndex, true);
break;
}
if ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
break;
}
}
codec.stop();
codec.release();
extractor.release();
}
public void stopPlay() {
isPlaying = false;
}
}
示例2:视频解码并保存
下面是一个使用MediaCodec进行视频解码并保存的示例:
public class VideoDecoder {
public void decode(String inputPath, String outputPath) throws IOException {
MediaExtractor extractor = new MediaExtractor();
extractor.setDataSource(inputPath);
int trackIndex = -1;
for (int i = 0; i < extractor.getTrackCount(); i++) {
MediaFormat format = extractor.getTrackFormat(i);
String mime = format.getString(MediaFormat.KEY_MIME);
if (mime.startsWith("video/")) {
extractor.selectTrack(i);
MediaCodec codec = MediaCodec.createDecoderByType(mime);
codec.configure(format, null, null, 0);
codec.start();
ByteBuffer[] inputBuffers = codec.getInputBuffers();
ByteBuffer[] outputBuffers = codec.getOutputBuffers();
MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
long timeOutUs = 10000;
FileOutputStream outputStream = new FileOutputStream(outputPath);
while (true) {
int inIndex = codec.dequeueInputBuffer(timeOutUs);
if (inIndex >= 0) {
ByteBuffer inputBuffer = inputBuffers[inIndex];
int size = extractor.readSampleData(inputBuffer, 0);
if (size < 0) {
codec.queueInputBuffer(inIndex, 0, 0, 0, MediaCodec.BUFFER_FLAG_END_OF_STREAM);
break;
} else {
codec.queueInputBuffer(inIndex, 0, size, extractor.getSampleTime(), 0);
extractor.advance();
}
}
int outIndex = codec.dequeueOutputBuffer(bufferInfo, timeOutUs);
while (outIndex >= 0) {
ByteBuffer outputBuffer = outputBuffers[outIndex];
byte[] outData = new byte[bufferInfo.size];
outputBuffer.get(outData);
outputStream.write(outData);
codec.releaseOutputBuffer(outIndex, false);
outIndex = codec.dequeueOutputBuffer(bufferInfo, timeOutUs);
}
}
codec.stop();
codec.release();
extractor.release();
outputStream.close();
break;
}
}
}
}
总结
通过MediaCodec进行硬解码,可以极大的优化视频解码的性能,并且在优化过程中可以根据不同的视频格式,使用不同的硬解码器以获得更好的性能。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Android音视频开发只硬件解码组件MediaCodec讲解 - Python技术站