Android笔记--MediaCodec(一)

         这一节主要来了解一下MediaCodec,Android MediaCodec 是 Android 平台提供的一个用于处理音频和视频数据的 API。它允许开发者对音频和视频数据进行编码和解码,支持多种格式和编解码器。MediaCodec API 通常用于实现实时音视频处理,如视频录制、播放、转码等。

基本概念:

编解码器(Codec):编解码器是负责将原始音视频数据压缩成特定格式(编码)或将压缩数据还原为原始数据(解码)的组件。
输入缓冲区(Input Buffers):用于向编解码器提供待处理的数据。
输出缓冲区(Output Buffers):编解码器处理后的数据存储在这里,开发者可以从这里读取处理后的数据。

优点:

高效的硬件加速:MediaCodec 支持硬件加速功能,这意味着它可以利用设备的硬件资源来提高音视频处理的效率和性能。硬件加速对于实现流畅且高质量的音视频处理至关重要,特别是在处理高分辨率或高帧率的内容时。
直接访问底层编解码器:通过 MediaCodec,开发者可以直接访问底层的编解码器,从而实现更高效的音视频处理。这有助于减少不必要的中间层开销,提高整体性能。
节省包体积:与常规的编解码库相比,MediaCodec 通常具有更小的体积,因此使用它可以帮助减小应用程序的包大小,降低用户的下载和安装成本。

缺点:
API 复杂性:MediaCodec 的 API 相对较为复杂,需要开发者具备较深的音视频处理知识和编程经验。这使得学习和使用 MediaCodec 的门槛相对较高,可能会增加开发难度和成本。
版本兼容性问题:MediaCodec 在不同版本的 Android 系统上可能存在兼容性问题。某些旧版本的 Android 系统可能不支持 MediaCodec 或支持有限,这可能导致开发者需要针对不同版本进行额外的适配工作。
硬件依赖:虽然 MediaCodec 支持硬件加速,但这也意味着它的性能受限于设备的硬件能力。不同设备的硬件性能差异可能导致音视频处理效果的差异,这要求开发者在设计和优化应用时需要考虑设备的硬件条件。

主要步骤

使用 MediaCodec API 通常涉及以下步骤:
创建编解码器实例:使用 MediaCodec.createDecoderByType 或 MediaCodec.createEncoderByType 方法创建编解码器实例。
配置编解码器:通过调用 MediaCodec.configure 方法配置编解码器的参数,如输入/输出格式、回调等。
启动编解码器:调用 MediaCodec.start 方法启动编解码器。

处理数据:
编码:从输入缓冲区获取数据,传递给编解码器进行编码,然后从输出缓冲区获取编码后的数据。
解码:将压缩数据写入输入缓冲区,从编解码器获取解码后的数据(通常写入输出缓冲区)。
停止和释放编解码器:完成数据处理后,调用 MediaCodec.stop 方法停止编解码器,并调用 MediaCodec.release 方法释放资源。

关键方法
configure:配置编解码器的参数。
start 和 stop:启动和停止编解码器。
dequeueInputBuffer 和 queueInputBuffer:获取输入缓冲区的索引并将数据送入编解码器。
dequeueOutputBuffer 和 releaseOutputBuffer:获取输出缓冲区的索引并读取处理后的数据,然后释放缓冲区。
getInputBuffers 和 getOutputBuffers:获取输入和输出缓冲区的直接引用。

栗子(设置编码器,输入原始视频帧,并从编码器获取编码后的数据):

通常需要在 AndroidManifest.xml 中添加如下权限:

<uses-permission android:name="android.permission.RECORD_AUDIO" />  
<uses-permission android:name="android.permission.CAMERA" />  
<uses-feature android:name="android.hardware.camera" />  
<uses-feature android:name="android.hardware.camera.autofocus" />
import android.media.MediaCodec;  
import android.media.MediaCodecInfo;  
import android.media.MediaFormat;  
import android.util.Log;  
import java.nio.ByteBuffer;  
  
public class VideoEncoder {  
    private static final String TAG = "VideoEncoderTest";  
    private MediaCodec encoder;  
    private boolean isRunning;  
  
    public void start(int width, int height, int bitrate) {  
        isRunning = true;  
        encoder = MediaCodec.createEncoderByType(MediaFormat.MIMETYPE_VIDEO_AVC);  
        MediaFormat format = MediaFormat.createVideoFormat(MediaFormat.MIMETYPE_VIDEO_AVC, width, height);  
        format.setInteger(MediaFormat.KEY_COLOR_FORMAT, MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface);  
        format.setInteger(MediaFormat.KEY_BIT_RATE, bitrate);  
        format.setInteger(MediaFormat.KEY_FRAME_RATE, 30);  
        format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 5);  
        encoder.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);  
        encoder.start();  
    }  
  
    public ByteBuffer[] getInputBuffers() {  
        return encoder.getInputBuffers();  
    }  
  
    public int dequeueInputBuffer(long timeoutUs) {  
        return encoder.dequeueInputBuffer(-1);  
    }  
  
    public void queueInputBuffer(int inputBufferIndex, int offset, int size, long presentationTimeUs, int flags) {  
        encoder.queueInputBuffer(inputBufferIndex, offset, size, presentationTimeUs, flags);  
    }  
  
    public ByteBuffer[] getOutputBuffers() {  
        return encoder.getOutputBuffers();  
    }  
  
    public MediaCodec.BufferInfo dequeueOutputBuffer(long timeoutUs) {  
        MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();  
        int outputBufferIndex = encoder.dequeueOutputBuffer(bufferInfo, timeoutUs);  
        while (outputBufferIndex >= 0) {  
            // 处理输出缓冲区的数据  
            encoder.releaseOutputBuffer(outputBufferIndex, false);  
            outputBufferIndex = encoder.dequeueOutputBuffer(bufferInfo, 0);  
        }  
        return bufferInfo;  
    }  
  
    public void stop() {  
        if (isRunning) {  
            isRunning = false;  
            encoder.stop();  
            encoder.release();  
            encoder = null;  
        }  
    }  
}

  • 4
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Android 中的 MediaCodec 类可以用于进行音频和视频的硬件加速编解码,也可以用于软解码。下面是一个使用 MediaCodec 进行软解码的简单示例: 1. 首先创建一个 MediaExtractor 对象,用于从媒体文件中提取音视频数据。 ```java MediaExtractor extractor = new MediaExtractor(); extractor.setDataSource(filePath); ``` 2. 根据需要解码的轨道类型(音频或视频),选择对应的轨道进行解码。 ```java 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("audio/")) { // 解码音频轨道 trackIndex = i; break; } else if (mime.startsWith("video/")) { // 解码视频轨道 trackIndex = i; break; } } if (trackIndex == -1) { // 没有找到相应的轨道,退出 return; } extractor.selectTrack(trackIndex); ``` 3. 创建 MediaCodec 对象并进行配置。 ```java MediaFormat format = extractor.getTrackFormat(trackIndex); MediaCodec codec = MediaCodec.createDecoderByType(format.getString(MediaFormat.KEY_MIME)); codec.configure(format, null, null, 0); codec.start(); ``` 4. 循环读取音视频数据并进行解码。读取的数据需要写入到 MediaCodec 的输入缓冲区中,然后调用 MediaCodec 的 dequeueInputBuffer() 方法获取已经被填充数据的输入缓冲区,并将其传递给 MediaCodec 进行解码。解码完成后,从 MediaCodec 的输出缓冲区中读取解码后的音视频数据。 ```java boolean inputEnd = false; boolean outputEnd = false; while (!outputEnd) { if (!inputEnd) { int inputBufferIndex = codec.dequeueInputBuffer(-1); if (inputBufferIndex >= 0) { ByteBuffer inputBuffer = codec.getInputBuffer(inputBufferIndex); int sampleSize = extractor.readSampleData(inputBuffer, 0); if (sampleSize < 0) { inputEnd = true; codec.queueInputBuffer(inputBufferIndex, 0, 0, 0, MediaCodec.BUFFER_FLAG_END_OF_STREAM); } else { codec.queueInputBuffer(inputBufferIndex, 0, sampleSize, extractor.getSampleTime(), 0); extractor.advance(); } } } int outputBufferIndex = codec.dequeueOutputBuffer(info, -1); if (outputBufferIndex >= 0) { if ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) { outputEnd = true; } ByteBuffer outputBuffer = codec.getOutputBuffer(outputBufferIndex); // 处理解码后的音视频数据 codec.releaseOutputBuffer(outputBufferIndex, false); } else if (outputBufferIndex == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) { MediaFormat newFormat = codec.getOutputFormat(); // 处理输出格式的变化 } } ``` 5. 最后,释放资源。 ```java codec.stop(); codec.release(); extractor.release(); ``` 这只是一个简单的示例,实际上使用 MediaCodec 进行软解码需要考虑很多细节,例如解码后的音视频数据的处理、异常情况的处理等。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值