Android MediaCodec 视频解码实战指南

在Android开发中,视频解码是一项基础而重要的任务。通过MediaCodec类,你可以解码不同格式的视频文件。本文将指导你逐步实现Android应用中的视频解码功能,包括必要的代码和注释。

流程概述

为了帮助你理解整个解码过程,下面是一个简单的流程表格:

步骤 描述
1. 初始化MediaCodec 创建MediaCodec实例并配置解码器
2. 配置输入数据 准备待解码的视频数据(例如:从文件中读取)
3. 提供输入数据 将输入数据发送到解码器
4. 获取输出数据 从解码器获取解码后的数据
5. 释放资源 在完成解码后释放MediaCodec和其他资源

详细步骤

接下来,我们将逐步实现这个流程中的每个步骤。请注意,在实现之前,确保你的项目中已经添加了必要的权限(例如,访问存储)以及依赖库。

1. 初始化MediaCodec

首先,我们需要创建一个MediaCodec实例并为其配置参数。

import android.media.MediaCodec;
import android.media.MediaFormat;
import android.view.Surface;

public class VideoDecoder {
    private MediaCodec mediaCodec;

    public void initDecoder(Surface surface) {
        try {
            // 创建MediaCodec实例,指定要解码的MIME类型
            mediaCodec = MediaCodec.createDecoderByType("video/avc");

            // 创建MediaFormat实例,设置解码参数
            MediaFormat format = MediaFormat.createVideoFormat("video/avc", 640, 480);
            format.setInteger(MediaFormat.KEY_COLOR_FORMAT, MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface);
            format.setInteger(MediaFormat.KEY_BIT_RATE, 400000);
            format.setInteger(MediaFormat.KEY_FRAME_RATE, 30);
            format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 5);
            
            // 配置解码器
            mediaCodec.configure(format, surface, null, 0);
            mediaCodec.start();  // 启动解码器
        } catch (IOException e) {
            e.printStackTrace();  // 异常处理
        }
    }
}

注释:本段代码中,我们创建了MediaCodec实例,通过createDecoderByType方法指定解码类型为H.264(即“video/avc”)。随后,设置了一系列解码参数,如分辨率、颜色格式及比特率。

2. 配置输入数据

接下来,我们需要准备输入数据,将其与MediaCodec关联。

import java.io.FileInputStream;
import java.nio.ByteBuffer;

public void feedInputData(String filePath) {
    try (FileInputStream fileInputStream = new FileInputStream(filePath)) {
        ByteBuffer[] inputBuffers = mediaCodec.getInputBuffers();
        int index = mediaCodec.dequeueInputBuffer(10000);  // 10ms超时
        if (index >= 0) {
            // 从文件读取数据并填充到inputBuffer
            ByteBuffer inputBuffer = inputBuffers[index];
            int bytesRead = fileInputStream.read(inputBuffer.array());
            if (bytesRead >= 0) {
                mediaCodec.queueInputBuffer(index, 0, bytesRead, 0, 0); // 将数据传入解码器
            }
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
}

注释:在此代码中,我们通过FileInputStream读取视频文件。在feedInputData方法中,我们获取InputBuffers数组,查找一个可用的输入缓冲区,并将从文件读取的数据填充到该缓冲区中。

3. 提供输入数据

调用queueInputBuffer方法将输入数据发送到MediaCodec进行解码。

public void startDecoding() {
    while (true) {
        // 处理输出数据
        MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
        int outputIndex = mediaCodec.dequeueOutputBuffer(bufferInfo, 10000); // 10ms超时

        if (outputIndex >= 0) {
            // 从outputBuffer获取解码后的视频帧数据
            mediaCodec.releaseOutputBuffer(outputIndex, true); // 释放输出缓冲区
        } else if (outputIndex == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
            // 输出格式发生变化
            MediaFormat newFormat = mediaCodec.getOutputFormat();
        } else if (outputIndex == MediaCodec.INFO_TRY_AGAIN_LATER) {
            // 处理其他情况
        }
    }
}

注释:此段代码中我们通过dequeueOutputBuffer方法获取解码后的视频帧。如果可用,我们将释放输出缓冲区,确保可以接收下一个解码后的数据。

4. 获取输出数据

在解码过程中,需要处理输出数据并决定如何呈现。

5. 释放资源

完成后确保释放MediaCodec和相关资源。

public void release() {
    if (mediaCodec != null) {
        mediaCodec.stop();   // 停止解码器
        mediaCodec.release(); // 释放解码器资源
        mediaCodec = null;   // 清空引用
    }
}

注释:在release方法中,我们停止并释放MediaCodec资源,确保不再留有内存泄露。

类图与流程图

类图

以下是类图:

classDiagram
class VideoDecoder {
    +void initDecoder(Surface surface)
    +void feedInputData(String filePath)
    +void startDecoding()
    +void release()
}

流程图

接下来是整个解码流程:

journey
    title 视频解码流程
    section 初始化解码器
      创建MediaCodec --> 准备格式设置: 5: MediaFormat
    section 输入数据处理
      读取视频文件 --> 填充输入数据: VideoDecoder
    section 输出数据处理
      解码输出数据 --> 释放输出缓冲区: MediaCodec
    section 资源释放
      停止MediaCodec --> 释放资源: VideoDecoder

结尾

至此,我们完成了Android MediaCodec视频解码的基本实现。在实际应用中,你可能还需要处理多线程、错误管理和视频渲染等复杂性。但本文所提供的基础已经为你打下了良好的基础。希望你能在实践中不断探索与深化视频解码的技术。如果遇到问题,可以随时查看官方文档或社区资源。祝你在Android开发之路上越走越远!