Android 音视频开发之 MediaCodec 解码 MP4 文件进行播放
同步方式
public static void decoder_VideoToSurface_Sync(Surface surface, String videoPath) throws Exception {
boolean inputBufferEnd = false;
boolean outputBufferEnd = false;
MediaExtractor mediaExtractor = new MediaExtractor();
mediaExtractor.setDataSource(videoPath);
int trackIndex = -1;
MediaFormat mediaFormat = null;
String mimeType = "";
int trackCount = mediaExtractor.getTrackCount();
for (int i = 0; i < trackCount; i++) {
mediaFormat = mediaExtractor.getTrackFormat(i);
mimeType = mediaFormat.getString(MediaFormat.KEY_MIME);
if (mimeType != null && mimeType.startsWith("video/")) {
trackIndex = i;
break;
}
}
if (trackIndex == -1) {
Log.e(TAG, "trackIndex == -1");
return;
}
mediaExtractor.selectTrack(trackIndex);
MediaCodec mediaCodec = MediaCodec.createDecoderByType(mimeType);
mediaCodec.configure(mediaFormat, surface, null, 0);
mediaCodec.start();
MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
int timeoutUs = 10_000;
while (!outputBufferEnd) {
int inputBufferIndex = mediaCodec.dequeueInputBuffer(timeoutUs);
if (inputBufferIndex >= 0) {
ByteBuffer inputBuffer = mediaCodec.getInputBuffer(inputBufferIndex);
if (inputBuffer != null) {
int sampleSize = mediaExtractor.readSampleData(inputBuffer, 0);
if (sampleSize >= 0) {
long sampleTime = mediaExtractor.getSampleTime();
int sampleFlags = mediaExtractor.getSampleFlags();
mediaCodec.queueInputBuffer(inputBufferIndex, 0, sampleSize, sampleTime, sampleFlags);
mediaExtractor.advance();
} else {
mediaCodec.queueInputBuffer(inputBufferIndex, 0, 0, 0, MediaCodec.BUFFER_FLAG_END_OF_STREAM);
inputBufferEnd = true;
}
}
}
int outputBufferIndex = mediaCodec.dequeueOutputBuffer(bufferInfo, timeoutUs);
if (outputBufferIndex >= 0) {
if ((bufferInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
outputBufferEnd = true;
}
ByteBuffer outputBuffer = mediaCodec.getOutputBuffer(outputBufferIndex);
if (outputBuffer == null) {
} else {
}
mediaCodec.releaseOutputBuffer(outputBufferIndex, true);
} else if (outputBufferIndex == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
MediaFormat newMediaFormat = mediaCodec.getOutputFormat();
}
}
mediaExtractor.release();
mediaCodec.stop();
mediaCodec.release();
}
异步方式
public static void decoder_VideoToSurface_Async(Surface surface, String videoPath) throws Exception {
AtomicBoolean inputBufferEnd = new AtomicBoolean(false);
AtomicBoolean outputBufferEnd = new AtomicBoolean(false);
MediaExtractor mediaExtractor = new MediaExtractor();
mediaExtractor.setDataSource(videoPath);
int trackIndex = -1;
MediaFormat mediaFormat = null;
String mimeType = "";
int trackCount = mediaExtractor.getTrackCount();
for (int i = 0; i < trackCount; i++) {
mediaFormat = mediaExtractor.getTrackFormat(i);
mimeType = mediaFormat.getString(MediaFormat.KEY_MIME);
if (mimeType != null && mimeType.startsWith("video/")) {
trackIndex = i;
break;
}
}
if (trackIndex == -1) {
Log.e(TAG, "trackIndex == -1");
return;
}
mediaExtractor.selectTrack(trackIndex);
MediaCodec mediaCodec = MediaCodec.createDecoderByType(mimeType);
mediaCodec.configure(mediaFormat, surface, null, 0);
mediaCodec.setCallback(new MediaCodec.Callback() {
@Override
public void onInputBufferAvailable(@NonNull MediaCodec mediaCodec, int inputBufferIndex) {
if (inputBufferIndex >= 0) {
ByteBuffer inputBuffer = mediaCodec.getInputBuffer(inputBufferIndex);
if (inputBuffer != null) {
int sampleSize = mediaExtractor.readSampleData(inputBuffer, 0);
if (sampleSize >= 0) {
long sampleTime = mediaExtractor.getSampleTime();
int sampleFlags = mediaExtractor.getSampleFlags();
mediaCodec.queueInputBuffer(inputBufferIndex, 0, sampleSize, sampleTime, sampleFlags);
mediaExtractor.advance();
} else {
mediaCodec.queueInputBuffer(inputBufferIndex, 0, 0, 0, MediaCodec.BUFFER_FLAG_END_OF_STREAM);
inputBufferEnd.set(true);
}
}
}
}
@Override
public void onOutputBufferAvailable(@NonNull MediaCodec mediaCodec, int outputBufferIndex, @NonNull MediaCodec.BufferInfo bufferInfo) {
if (outputBufferIndex >= 0) {
if ((bufferInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
outputBufferEnd.set(true);
}
ByteBuffer outputBuffer = mediaCodec.getOutputBuffer(outputBufferIndex);
if (outputBuffer == null) {
} else {
}
mediaCodec.releaseOutputBuffer(outputBufferIndex, true);
}
}
@Override
public void onError(@NonNull MediaCodec mediaCodec, @NonNull MediaCodec.CodecException e) {
Log.e(TAG, "onError: ", e);
}
@Override
public void onOutputFormatChanged(@NonNull MediaCodec mediaCodec, @NonNull MediaFormat mediaFormat) {
MediaFormat newMediaFormat = mediaCodec.getOutputFormat();
}
});
mediaCodec.start();
while (!outputBufferEnd.get()) {
Thread.sleep(10);
}
mediaExtractor.release();
mediaCodec.stop();
mediaCodec.release();
}