Android中初始化Codec2的具体流程

Android系统中的MediaCodec架构提供了一种直接操作显卡解码器的方式。在Android 5.0之后,MediaCodec架构提供了更为底层的codec,即Codec2,可以方便地实现硬件加速的解码和编码,从而能够提高媒体文件的处理速度。

在Android中初始化Codec2的具体流程如下:

1.获取Codec2的列表

如下代码所示,可以通过MediaCodecList类获取Codec2的列表。然后通过iterate方法,获取系统中所有支持的codec信息。

MediaCodecList codecList = new MediaCodecList(MediaCodecList.REGULAR_CODECS);
for (MediaCodecInfo codecInfo : codecList.getCodecInfos()) {
    if (!codecInfo.isEncoder()) {
        continue;
    }
    String[] types = codecInfo.getSupportedTypes();
    for (String type : types) {
        if (!type.equals(Mime. VIDEO_H264)) {
            continue;
        }
        // Get the default capabilities for an H.264 encoder
        CodecCapabilities capabilities =
                codecInfo.getCapabilitiesForType(type);
        // Check the resolution supported by hardware codec and your device
        int width = 1280;
        int height = 720;
        if (capabilities.isFormatSupported(new MediaFormat().
                setInteger(MediaFormat.KEY_WIDTH, width).
                setInteger(MediaFormat.KEY_HEIGHT, height).
                setString(MediaFormat.KEY_MIME, type))) {
            Log.i(TAG, "Found " + codecInfo.getName() + " supporting " + type + " for "
                    + width + "x" + height + " with default capabilities: " + capabilities);
        }
    }
}

2.创建Codec2

通过Codec2的名称创建MediaCodec对象,并将其配置为编码器或解码 器,如下所示:

MediaCodec codec = MediaCodec.createByCodecName(codecInfo.getName());
MediaFormat inputFormat = MediaFormat.createVideoFormat(Mime.VIDEO_H264,
        1280, 720);
codec.configure(inputFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
codec.start();

3.接收数据并编码

通过configure方法配置设置编码器的输入格式,然后通过MediaCodec中的encoderInputBuffer,从交换数组中获取有效的输入数据进行编码,最后将编码后的数据放入MediaCodec的输出缓冲区中,如下所示:

ByteBuffer[] encoderInputBuffer = codec.getInputBuffers();
ByteBuffer[] encoderOutputBuffer = codec.getOutputBuffers();
int timeoutUs = 10000;
while (true) {
    int inputBufferIndex = codec.dequeueInputBuffer(timeoutUs);
    if (inputBufferIndex >= 0) {
        ByteBuffer inputBuffer = encoderInputBuffer[inputBufferIndex];
        //Fill the ByteBuffer with your raw data
        int rawBytesDataLength = getAudioDataLength();
        inputBuffer.clear();
        byte[] rawBytesData = getRawBytesData();
        inputBuffer.put(rawBytesData, 0, rawBytesDataLength);
        codec.queueInputBuffer(inputBufferIndex, 0, rawBytesDataLength, 0, 0);
    }
    MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
    int outputBufferIndex = codec.dequeueOutputBuffer(bufferInfo, timeoutUs);
    if (outputBufferIndex >= 0) {
        ByteBuffer outputBuffer = encoderOutputBuffer[outputBufferIndex];
        // Output the encoded frame here to other sources
        codec.releaseOutputBuffer(outputBufferIndex, false);
    }
}

以上是初始化Codec2的具体流程。其中,第二步和第三步中的核心代码,就是通过configure方法来进行配置,然后在输入数据中获取有效数据,经过编码后输出到输出缓冲区中。

下面是两个示例:

示例一:实现将本地视频转换为h.264编码格式并保存到文件中:

MediaCodec codec = MediaCodec.createEncoderByType("video/avc");
int width = 640;
int height = 480;
int frameRate = 30;
int bitRate = 1024 * 1024;
int colorFormat = MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Flexible;
int iFrameInterval = 1;
MediaFormat format = MediaFormat.createVideoFormat("video/avc", width, height);
format.setInteger(MediaFormat.KEY_BIT_RATE, bitRate);
format.setInteger(MediaFormat.KEY_FRAME_RATE, frameRate);
format.setInteger(MediaFormat.KEY_COLOR_FORMAT, colorFormat);
format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, iFrameInterval);
codec.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
codec.start();

ByteBuffer[] inputBuffers = codec.getInputBuffers();
ByteBuffer[] outputBuffers = codec.getOutputBuffers();
MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
// Do video decoding here until we get EOS from the decoder
boolean done = false;
while (done) {
    // Do video encoding here
    //extract data from input buffer
    int inputBufferIndex = codec.dequeueInputBuffer(10000);
    if (inputBufferIndex >= 0) {
        ByteBuffer inputBuffer = inputBuffers[inputBufferIndex];
        byte[] newInputData = getInputData();
        inputBuffer.put(newInputData);
        codec.queueInputBuffer(inputBufferIndex, 0, newInputData.length, 0, 0);
    }
    //continue dequeueing and encoding until we get an EOF
    int outputBufferIndex = codec.dequeueOutputBuffer(bufferInfo, 10000);
    while (outputBufferIndex != -1) {
        ByteBuffer outputBuffer = outputBuffers[outputBufferIndex];
        //output the encoded video data
        outputToFile(outputBuffer);
        codec.releaseOutputBuffer(outputBufferIndex, false);
        outputBufferIndex = codec.dequeueOutputBuffer(bufferInfo, 0);
    }
    if ((bufferInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
        done = true;
    }
}
codec.stop();
codec.release();

示例二:实现通过异步线程进行数据的编码:

private static class EncodingTask extends AsyncTask<Void, Void, Void> {
    MediaCodec codec;
    ByteBuffer[] inputBuffers;
    ByteBuffer[] outputBuffers;
    MediaCodec.BufferInfo bufferInfo;

    public EncodingTask() {
        codec = MediaCodec.createEncoderByType("video/avc");
        int width = 640;
        int height = 480;
        int frameRate = 30;
        int bitRate = 1024 * 1024;
        int colorFormat = MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Flexible;
        int iFrameInterval = 1;
        MediaFormat format = MediaFormat.createVideoFormat("video/avc", width, height);
        format.setInteger(MediaFormat.KEY_BIT_RATE, bitRate);
        format.setInteger(MediaFormat.KEY_FRAME_RATE, frameRate);
        format.setInteger(MediaFormat.KEY_COLOR_FORMAT, colorFormat);
        format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, iFrameInterval);
        codec.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
        codec.start();

        int timeoutUs = 10000;
        inputBuffers = codec.getInputBuffers();
        outputBuffers = codec.getOutputBuffers();
        bufferInfo = new MediaCodec.BufferInfo();

        // Put data into our queue
        offerEncoderInput(bufferInfo, true);
    }

    @Override
    protected Void doInBackground(Void... params) {
        while (true) {
            if (isCancelled()) {
                return null;
            }
            int outputBufferIndex = codec.dequeueOutputBuffer(bufferInfo, timeoutUs);
            if (outputBufferIndex == MediaCodec.INFO_TRY_AGAIN_LATER) {
                continue;
            } else if (outputBufferIndex == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
                Log.d(TAG, "encoder output format changed: " + codec.getOutputFormat());
                continue;
            } else if (outputBufferIndex < 0) {
                continue;
            }
            ByteBuffer outputBuffer = codec.getOutputBuffers()[outputBufferIndex];
            // Put data in the buffer

            codec.releaseOutputBuffer(outputBufferIndex, false);
            offerEncoderInput(bufferInfo, false);
        }
    }

    private void offerEncoderInput(MediaCodec.BufferInfo bufferInfo, boolean eos) {
        while (true) {
            int inputBufferIndex = codec.dequeueInputBuffer(timeoutUs);
            if (inputBufferIndex == MediaCodec.INFO_TRY_AGAIN_LATER) {
                continue;
            }
            if (eos) {
                codec.queueInputBuffer(inputBufferIndex, 0, 0, 0, MediaCodec.BUFFER_FLAG_END_OF_STREAM);
                break;
            }
            ByteBuffer inputBuffer = codec.getInputBuffers()[inputBufferIndex];
            // Put data into input buffer

            codec.queueInputBuffer(inputBufferIndex, bufferInfo.offset, bufferInfo.size,
                    bufferInfo.presentationTimeUs, bufferInfo.flags);
            break;
        }
    }
}

以上两个示例,分别实现了将本地视频转换为h.264编码格式及通过异步线程进行数据编码,并通过设置各种参数进行优化处理,显著提高了视频编码效率。其中,初始化Codec2的流程,包括获取Codec2的列表、创建Codec2以及接收数据并进行编码,都是必不可少的步骤。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Android中初始化Codec2的具体流程 - Python技术站

(0)
上一篇 2023年6月20日
下一篇 2023年6月20日

相关文章

  • Linux 下sftp配置之密钥方式登录详解

    Linux 下 SFTP 配置之密钥方式登录详解 本文将介绍如何在 Linux 系统中使用密钥方式登录 SFTP。 什么是密钥方式登录? 密钥方式登录是一种比传统的用户名和密码登录更加安全的方式。在密钥方式中,用户首先需要创建一对密钥(公钥和私钥),将公钥上传到服务器端,然后使用私钥进行登录。 生成密钥对 可以使用 ssh-keygen 命令来生成密钥对。该…

    other 2023年6月27日
    00
  • jquery绑定input的change事件

    jQuery绑定input的change事件 在Web开发中,我们经常需要使用jQuery绑定input的change事件,以便在输入框内容发生变化时执行一些操作。以下是jQuery绑定input的change事件的完整攻略。 步骤 以下是jQuery绑定input的change事件的步骤: 使用jQuery选择器选择要绑定change事件的input元素。…

    other 2023年5月6日
    00
  • jwt——生成token、解析token的简单工具类

    以下是关于“JWT——生成Token、解析Token的简单工具类”的完整攻略,过程中包含两个示例。 背景 在Web开发中,JWT(JSON Web Token)是一种常用身份验证和授权机制。攻略将介绍如何使用Java编写一个简单的JWT工具类,用于生成Token和解析Token。 基本原理 在Java,我们可以使用第三方库jjwt来生成和解析JWT。具体步骤…

    other 2023年5月9日
    00
  • linuxcomposer的使用

    Linux Composer的使用完整攻略 Linux Composer是一款用于创建和管理Linux发行版的工具,可以帮助开发人员快速构建自己的Linux发行版。本文将提供Linux Composer的使用完整攻略,包括以下步骤: 安装Linux Composer 创建Linux发行版 定制Linux发行版 构建Linux发行版 测试Linux发行版 同时…

    other 2023年5月9日
    00
  • Android实现启动引导图

    Android实现启动引导图攻略 启动引导图是在用户第一次打开应用程序时显示的一组屏幕,用于向用户展示应用程序的功能和特性。下面是实现启动引导图的完整攻略。 步骤1:准备资源 首先,您需要准备启动引导图所需的资源,包括图片、文本等。将这些资源添加到您的项目的res目录下。 步骤2:创建引导图布局 在res/layout目录下创建一个新的布局文件,用于显示引导…

    other 2023年8月21日
    00
  • Redis配置文件redis.conf详细配置说明

    下面是Redis配置文件redis.conf详细配置说明: Redis配置文件详细配置说明 Redis的配置文件是redis.conf,在安装Redis后,该配置文件位置一般在/etc/redis/redis.conf或者/usr/local/etc/redis.conf。Redis的配置文件中包含了很多配置,下面将逐一进行说明。 基础配置 daemoniz…

    other 2023年6月25日
    00
  • 日常整理linux常用命令大全(收藏)

    日常整理Linux常用命令大全(收藏) 回答者以Markdown形式记录了对Linux命令的整理与总结,包括Linux常用命令、Shell脚本、网络命令、常用工具等方面。 Linux常用命令 回答者整理记录Linux常用命令,建议先掌握这些命令。 常用命令包括: 目录操作: ls #查看目录内容 cd dir #切换到目录dir mkdir dir #创建新…

    other 2023年6月26日
    00
  • Powershell中创建自定义对象例子

    以下是使用标准的Markdown格式文本,详细讲解在PowerShell中创建自定义对象的完整攻略: PowerShell中创建自定义对象的方法 使用New-Object命令创建自定义对象:PowerShell中可以使用New-Object命令创建自定义对象。按照以下步骤进行操作: 定义自定义对象的属性:首先,需要定义自定义对象的属性。可以使用Add-Mem…

    other 2023年10月15日
    00
合作推广
合作推广
分享本页
返回顶部