在Android开发中,使用MediaCodec
和MediaExtractor
来播放视频和音频是一种比较底层的方法,它可以给你更多的控制权,比如处理非标准的媒体格式或者实现特殊的播放效果。下面是一个基本的步骤和代码示例,帮助你理解如何使用这两个类来播放媒体文件。
MediaExtractor
提取媒体数据MediaExtractor
可以从多种来源(如文件或网络流)中分离视频和音频轨道。
MediaExtractor extractor = new MediaExtractor();
try {
// 设置数据源
extractor.setDataSource(filePath);
int trackCount = extractor.getTrackCount();
int videoTrackIndex = -1;
int audioTrackIndex = -1;
// 查找视频轨和音频轨
for (int i = 0; i < trackCount; i++) {
MediaFormat format = extractor.getTrackFormat(i);
String mime = format.getString(MediaFormat.KEY_MIME);
if (mime.startsWith("video/")) {
videoTrackIndex = i;
} else if (mime.startsWith("audio/")) {
audioTrackIndex = i;
}
}
if (videoTrackIndex == -1 || audioTrackIndex == -1) {
throw new IllegalArgumentException("No video or audio track found in file");
}
// 选择轨道
extractor.selectTrack(videoTrackIndex);
// 可以选择性地处理音频轨道
} catch (IOException e) {
e.printStackTrace();
}
MediaCodec
解码媒体数据MediaCodec
用于解码视频和音频数据。
// 创建解码器
MediaCodec videoCodec = MediaCodec.createDecoderByType(videoMime);
videoCodec.configure(videoFormat, surface, null, 0);
videoCodec.start();
// 缓冲区处理
ByteBuffer[] inputBuffers = videoCodec.getInputBuffers();
ByteBuffer[] outputBuffers = videoCodec.getOutputBuffers();
while (!eosReceived) {
int inIndex = videoCodec.dequeueInputBuffer(10000);
if (inIndex >= 0) {
ByteBuffer buffer = inputBuffers[inIndex];
// 从extractor读取数据到buffer中
int sampleSize = extractor.readSampleData(buffer, 0);
if (sampleSize < 0) {
// 数据读取完毕
videoCodec.queueInputBuffer(inIndex, 0, 0, 0, MediaCodec.BUFFER_FLAG_END_OF_STREAM);
eosReceived = true;
} else {
videoCodec.queueInputBuffer(inIndex, 0, sampleSize, extractor.getSampleTime(), 0);
extractor.advance();
}
}
// 获取解码后的数据
MediaCodec.BufferInfo info = new MediaCodec.BufferInfo();
int outIndex = videoCodec.dequeueOutputBuffer(info, 10000);
switch (outIndex) {
case MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED:
outputBuffers = videoCodec.getOutputBuffers();
break;
case MediaCodec.INFO_OUTPUT_FORMAT_CHANGED:
// Subsequent data will conform to new format.
break;
case MediaCodec.INFO_TRY_AGAIN_LATER:
// No output available yet
break;
default:
// 解码成功,使用outputBuffers[outIndex]中的数据
videoCodec.releaseOutputBuffer(outIndex, true); // Surface作为目标时,设置为true
break;
}
}
这只是一个基本的框架,实际应用中可能需要更复杂的处理,比如处理不同格式的兼容性问题、动态输入源的处理等。
领取专属 10元无门槛券
手把手带您无忧上云