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日

相关文章

  • BigDecimal类

    BigDecimal类 在Java中,使用float或double类型来表示小数时,由于浮点数本质上是二进制的,因此在进行精确计算时可能会存在精度丢失的问题,这对于需要精确计算的场景来说是不能接受的。 为了解决这一问题,Java中提供了BigDecimal类,即可以精确表示数字的高精度类。本篇文章将分为以下几个部分介绍BigDecimal类的使用。 1. B…

    其他 2023年3月28日
    00
  • Moqui简介

    Moqui是一个开源的企业应用程序平台,它提供了一系列的工具和框架,可以帮助开发人员快速构建企业级应用程序。以下是“Moqui简介”的完整攻略: Moqui的特点 Moqui具有以下特点: 基于Java和Groovy语言,可以在JVM上运行。 提供了一系列的工具和框架,包括实体引擎、工作流引擎、规则引擎等。 支持多种数据库,包括MySQL、PostgreSQ…

    other 2023年5月5日
    00
  • 在 Vue 中使用 iframe 嵌套页面的步骤

    当在Vue中使用iframe嵌套页面时,可以按照以下步骤进行操作: 在Vue组件中添加iframe元素:在Vue组件的模板中,使用<iframe>标签添加一个iframe元素。可以通过设置src属性来指定要嵌套的页面的URL。 示例代码: <template> <div> <h1>主页面</h1> …

    other 2023年7月27日
    00
  • Win10非正常关机使用自动修复陷入无限重启该怎么办?

    Win10非正常关机使用自动修复陷入无限重启该怎么办? 问题描述 在Windows 10系统中,如果在非正常关机的情况下出现自动修复的情况,可能导致系统陷入无限重启,让电脑无法正常启动。那么,该如何解决这个问题呢? 解决办法 1.使用高级选项菜单中的“修复你的电脑”选项 在电脑启动时连按 F8 键,进入高级启动选项菜单。 在菜单中选择“修复你的电脑”选项,按…

    other 2023年6月27日
    00
  • ReentrantLock获取锁释放锁的流程示例分析

    ReentrantLock是一个可重入锁,和synchronized关键字一样,在Java中被广泛使用。但是,相较于synchronized关键字,ReentrantLock在一些场景下表现得更好,比如可以响应中断、可以指定尝试获取锁的时间等等。 ReentrantLock获取锁和释放锁是一个比较重要的知识点,我们需要深入了解其工作流程。下面,我们将通过两个…

    other 2023年6月27日
    00
  • springAOP中用joinpoint获取切入点方法的参数操作

    以下是关于在Spring AOP中使用JoinPoint获取切入点方法参数的操作的详细攻略: Spring AOP中使用JoinPoint获取切入点方法参数 在Spring AOP中,可以使用JoinPoint对象来获取切入点方法的参数。JoinPoint是Spring AOP框架提供的一个接口,它包含了切入点方法的相关信息,包括方法名、参数等。 下面是使用…

    other 2023年10月13日
    00
  • 用js正确判断用户名cookie是否存在的方法

    判断用户名Cookie是否存在的方法主要涉及以下几个步骤: 1.获取当前网页中所有的Cookie2.遍历Cookie,查找是否存在用户名的Cookie3.如果存在,则说明用户已经登录;否则,说明用户未登录 下面以 JavaScript 为例,介绍具体的实现方法。 获取当前网页中所有的Cookie 可以使用 document.cookie 获取当前网页中所有的…

    other 2023年6月27日
    00
  • vundle简介安装

    Vundle 简介安装 Vundle 是一个 Vim 插件管理器,可以通过它来轻松地安装和升级 Vim 插件。本文将介绍 Vundle 的基本用法。 安装 Vundle 在使用 Vundle 之前,需要先安装 Vundle。可以通过 Git 命令将 Vundle 下载到本地: git clone https://github.com/VundleVim/Vu…

    其他 2023年3月29日
    00
合作推广
合作推广
分享本页
返回顶部