Android中初始化Codec2的具体流程

yizhihongxing

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日

相关文章

  • JVM 方法调用之动态分派(详解)

    JVM 方法调用之动态分派详解 动态分派是什么? 动态分派是指在运行时根据实际类型来确定被调用的方法。 在Java中,方法调用有两种形式:静态调用和动态调用。静态调用是指在编译期已经确定了实际调用的方法,而动态调用则是指在运行时根据实际类型来确定所要调用的方法。 为什么需要动态分派? Java是一门静态类型语言,因此在编译期间类型已经确定。但是,Java中的…

    other 2023年6月26日
    00
  • MinGW-w64 C/C++编译器下载和安装的方法步骤(入门教程)

    MinGW-w64 C/C++编译器下载和安装的方法步骤(入门教程) MinGW-w64是可以在各种Windows操作系统上编译C和C++代码的工具集。本文将谈论下载和安装MinGW-w64 C/C++编译器的具体步骤。 步骤1:下载MinGW-w64安装文件 打开MinGW-w64的下载页面:https://sourceforge.net/projects…

    other 2023年6月26日
    00
  • Android 内存溢出和内存泄漏的问题

    Android 内存溢出和内存泄漏问题攻略 1. 内存溢出问题 内存溢出是指应用程序在申请内存时,没有足够的可用内存供其使用,导致程序崩溃或异常终止。以下是解决内存溢出问题的一些步骤: 步骤一:分析内存使用情况 使用Android Profiler或其他性能分析工具来监测应用程序的内存使用情况。观察内存使用的峰值和变化趋势,找出可能导致内存溢出的原因。 步骤…

    other 2023年8月1日
    00
  • 鸿蒙系统官方刷机教程

    以下是鸿蒙系统官方刷机教程的完整攻略: 鸿蒙系统官方刷机教程 鸿蒙系统是华为公司开发的一款操作系统,具有高效、安全、智能等特点。以下是鸿蒙系统官方刷机教的详细步骤: 1. 下载鸿蒙系统镜像 首先,您需要从鸿蒙系统官方网站下载鸿蒙系统镜像。您可以在鸿蒙系统官方网站上到下载鸿蒙系统镜像的详细步骤。 2. 准备刷机工具 在下载鸿蒙系统镜像后,您需要准备刷机工具。以…

    other 2023年5月7日
    00
  • vmware虚拟机将英文改成中文的方法

    vmware虚拟机将英文改成中文的方法 在使用vmware虚拟机的过程中,有时候我们需要将界面从英文改成中文,方便我们更好地使用。这里介绍一下在vmware虚拟机中将英文界面改成中文的方法。 步骤一:下载中文语言包 首先,我们需要在官网或其他渠道下载合适版本的中文语言包。需要注意的是,所下载的语言包版本必须和当前使用的vmware版本一致。 步骤二:安装中文…

    其他 2023年3月28日
    00
  • 正则表达式模式匹配字符串基础知识

    正则表达式模式匹配字符串基础知识 正则表达式是一种可以用于匹配字符串的模式,它可以用于搜索、替换和验证输入的文本内容。本文将详细讲解正则表达式模式匹配字符串的基础知识,包括正则表达式语法、常用元字符和模式示例等。 正则表达式语法 正则表达式是由普通字符和元字符组成的模式,用于匹配字符串中的文本内容。常见的正则表达式语法包括: 普通字符:表示文本中的普通字符,…

    other 2023年6月20日
    00
  • Java正则表达式之Pattern类实例详解

    当然!下面是关于\”Java正则表达式之Pattern类实例详解\”的完整攻略: Java正则表达式之Pattern类实例详解 在Java中,可以使用Pattern类来创建和使用正则表达式。以下是两个示例: 示例1:使用Pattern类进行匹配 import java.util.regex.*; public class RegexExample { pub…

    other 2023年8月19日
    00
  • 怎么把mp4转换成mp3完美解决方案

    当需要将视频文件中的音频提取出来时,我们可以把mp4格式的视频转换为mp3格式的音频文件。下面是一些简单的步骤来转换Mp4至mp3。 步骤1: 下载并安装FFmpeg 首先我们需要下载和安装FFmpeg。FFmpeg是一种用于处理音频、视频和图像的免费开源软件库,可在多个平台上运行。尽管FFmpeg没有界面,但它可以通过命令行实现许多编解码和编辑任务。对于W…

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