使用 MediaCodec 在 Android 上进行硬解码

要使用 MediaCodec 在 Android 上进行硬解码,并获取 RGBA 数据,你可以按照以下步骤进行操作:

创建 MediaExtractor 对象并设置要解码的 MP4 文件路径:

MediaExtractor extractor = new MediaExtractor();
extractor.setDataSource(filePath);

根据需要选择音频或视频轨道:

int trackCount = extractor.getTrackCount();
int trackIndex = -1;
for (int i = 0; i < trackCount; i++) {MediaFormat format = extractor.getTrackFormat(i);String mime = format.getString(MediaFormat.KEY_MIME);if (mime.startsWith("video/")) {trackIndex = i;break;}
}
if (trackIndex >= 0) {extractor.selectTrack(trackIndex);
}

创建 MediaCodec 对象并配置解码器:

MediaFormat format = extractor.getTrackFormat(trackIndex);
String mime = format.getString(MediaFormat.KEY_MIME);
MediaCodec codec = MediaCodec.createDecoderByType(mime);
codec.configure(format, null, null, 0);
codec.start();

循环解码并获取 RGBA 数据:

MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
boolean isEOS = false;
while (!isEOS) {int inputBufferIndex = codec.dequeueInputBuffer(timeoutUs);if (inputBufferIndex >= 0) {ByteBuffer inputBuffer = codec.getInputBuffer(inputBufferIndex);int sampleSize = extractor.readSampleData(inputBuffer, 0);if (sampleSize < 0) {codec.queueInputBuffer(inputBufferIndex, 0, 0, 0, MediaCodec.BUFFER_FLAG_END_OF_STREAM);isEOS = true;} else {long presentationTimeUs = extractor.getSampleTime();codec.queueInputBuffer(inputBufferIndex, 0, sampleSize, presentationTimeUs, 0);extractor.advance();}}int outputBufferIndex = codec.dequeueOutputBuffer(bufferInfo, timeoutUs);if (outputBufferIndex >= 0) {ByteBuffer outputBuffer = codec.getOutputBuffer(outputBufferIndex);// 解码后的数据位于 outputBuffer 中,根据需要进行 RGBA 数据的提取和处理// outputBuffer 中的数据格式可能是 YUV 或其他格式,需要根据解码器设置的输出格式进行相应的转换codec.releaseOutputBuffer(outputBufferIndex, false);} else if (outputBufferIndex == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {// 解码器输出格式已更改,可以通过 codec.getOutputFormat() 获取新的格式}
}

在上述代码中,你需要根据解码器输出的数据格式进行相应的转换,以获取 RGBA 数据。具体的转换流程和代码取决于解码器输出的数据格式和你的需求。

需要注意的是,硬解码的支持和性能可能因设备、Android 版本和视频编码格式的不同而有所差异。确保你的设备支持硬解码,并且适当处理解码器的输入和输出缓冲区。

以下是完整代码:

import android.media.MediaCodec;
import android.media.MediaExtractor;
import android.media.MediaFormat;
import android.util.Log;import java.nio.ByteBuffer;public class MP4Decoder {private static final int TIMEOUT_US = 10000;private static final String TAG = "MP4Decoder";public interface FrameCallback {void onFrameDecoded(byte[] rgbaData, int width, int height);}public static void decodeMP4(String filePath, FrameCallback callback) {new Thread(() -> {MediaExtractor extractor = new MediaExtractor();try {extractor.setDataSource(filePath);int trackIndex = selectVideoTrack(extractor);if (trackIndex < 0) {return;}MediaFormat format = extractor.getTrackFormat(trackIndex);String mime = format.getString(MediaFormat.KEY_MIME);MediaCodec codec = MediaCodec.createDecoderByType(mime);codec.configure(format, null, null, 0);codec.start();MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();boolean isEOS = false;while (!isEOS) {int inputBufferIndex = codec.dequeueInputBuffer(TIMEOUT_US);if (inputBufferIndex >= 0) {ByteBuffer inputBuffer = codec.getInputBuffer(inputBufferIndex);int sampleSize = extractor.readSampleData(inputBuffer, 0);if (sampleSize < 0) {codec.queueInputBuffer(inputBufferIndex, 0, 0, 0, MediaCodec.BUFFER_FLAG_END_OF_STREAM);isEOS = true;} else {long presentationTimeUs = extractor.getSampleTime();codec.queueInputBuffer(inputBufferIndex, 0, sampleSize, presentationTimeUs, 0);extractor.advance();}}int outputBufferIndex = codec.dequeueOutputBuffer(bufferInfo, TIMEOUT_US);if (outputBufferIndex >= 0) {ByteBuffer outputBuffer = codec.getOutputBuffer(outputBufferIndex);// 解码后的数据位于 outputBuffer 中,根据需要进行 RGBA 数据的提取和处理// outputBuffer 中的数据格式可能是 YUV 或其他格式,需要根据解码器设置的输出格式进行相应的转换byte[] rgbaData = convertToRGBA(outputBuffer, format);int width = format.getInteger(MediaFormat.KEY_WIDTH);int height = format.getInteger(MediaFormat.KEY_HEIGHT);callback.onFrameDecoded(rgbaData, width, height);codec.releaseOutputBuffer(outputBufferIndex, false);} else if (outputBufferIndex == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {// 解码器输出格式已更改,可以通过 codec.getOutputFormat() 获取新的格式}}} catch (Exception e) {e.printStackTrace();} finally {extractor.release();}}).start();}private static int selectVideoTrack(MediaExtractor extractor) {int trackCount = extractor.getTrackCount();int trackIndex = -1;for (int i = 0; i < trackCount; i++) {MediaFormat format = extractor.getTrackFormat(i);String mime = format.getString(MediaFormat.KEY_MIME);if (mime.startsWith("video/")) {trackIndex = i;break;}}if (trackIndex >= 0) {extractor.selectTrack(trackIndex);}return trackIndex;}private static byte[] convertToRGBA(ByteBuffer buffer, MediaFormat format) {// 根据解码器设置的输出格式进行 RGBA 数据的提取和处理// 这里只是一个示例,实际的转换过程可能会更复杂,取决于输出格式和需求int width = format.getInteger(MediaFormat.KEY_WIDTH);int height = format.getInteger(MediaFormat.KEY_HEIGHT);int remaining = buffer.remaining();byte[] rgbaData = new byte[remaining];buffer.rewind();buffer.get(rgbaData);Log.i(TAG, "convertToRGBA: count:" + width + "; " + height + "; " + remaining);// todo: 进行 YUV 到 RGBA 的转换return rgbaData;}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/4078.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

数据结构(data structure)(1)链表和线性表

类和对象 对象将数据和操作打包在一起&#xff0c;类描述了这一切 用构造器创建(实例化)对象 类和类之间的关系 -关联&#xff08;组合&#xff0c;聚集&#xff09; -泛化private class Student{protected String name;protected int age;protected int ability;public Studen…

安卓ComponentName简介及使用

目录 一、ComponentName是什么&#xff1f;二、类分析2.1 构造方法2.2 重点方法 三、ComponentName的使用 一、ComponentName是什么&#xff1f; ComponentName&#xff0c;顾名思义&#xff0c;就是组件名称&#xff0c;用于表示Android应用程序组件的名称。在Android开发中&…

航空企业数字化解决方案(207页PPT)

一、资料描述 航空企业数字化解决方案是一项针对航空公司在数字化转型过程中所面临挑战的全面应对策略&#xff0c;旨在通过先进的信息技术提升航空企业的运营效率、客户服务水平以及市场竞争力。这份207页的PPT详细介绍了航空企业数字化的各个方面&#xff0c;包括关键技术的…

Web3技术解析:区块链在去中心化应用中的角色

引言 在过去几年中&#xff0c;Web3技术已经成为了互联网领域的一个热门话题。作为区块链技术的延伸&#xff0c;Web3不仅仅是数字货币的代名词&#xff0c;更是一个能够为各种应用提供去中心化解决方案的强大工具。本文将深入探讨区块链在Web3去中心化应用中的关键角色&#…

ubuntu查看opencveigen

ubuntu查看opencv&eigen&cmake版本的方法 eigen eigen版本号在/usr/include/eigen3/Eigen/src/Core/util/Macros.h文件中&#xff0c;下图代表版本3.3.7 opencv版本 pkg-config --modversion opencv4也可能最后的字符串是opencv2&#xff0c;opencv

R语言 数据框的长、宽格式转换

Converting data between wide and long format 在宽、长格式之间转换数据 R语言中的大多数函数希望数据是长格式 但是&#xff0c;像 SPSS 通常使用宽格式数据 当你想把将数据从宽转换为长格式 常用的有两种方法&#xff1a; 1、gather() 和 spread() 来自 tidyr 包。 2、me…

W801学习笔记十二:掌机进阶V3版本之驱动(PSRAM/SD卡)

本次升级添加了两个模块&#xff0c;现在要把他们驱动起来。 一&#xff1a;PSRAM 使用SDK自带的驱动&#xff0c;我们只需要写一个初始化函数&#xff0c;并在其中添加一些自检代码。 void psram_heap_init(){wm_psram_config(0);//实际使用的psram管脚选择0或者1&#xff…

美团:搜索推荐算法工程师

目录 机器学习、深度学习和强化学习 迁移学习: 强化学习: 可解释性推荐:

中小学生如何开始创办谷歌?

现在财富自由这个词很火&#xff0c;因为每个人都想让自己能够摆脱朝九晚五工作的束缚。而通往财富自由的最佳路径——那就是创办自己的公司。 这不仅仅是关于金钱&#xff0c;更是关于掌控自己的未来&#xff0c;实现个人价值的最大化。 你是否曾梦想过自己的创意能够颠覆整…

Java学习路线及自我规划

荒废了一段时间&#xff0c;这段时间的总结开始了JavaWeb的学习但是困难重重&#xff0c;例如Maven&#xff0c;Vue的路由等&#xff0c;所以我反省了一段时间&#xff0c;因为基础薄弱&#xff0c;加之学习的资源是速成视频&#xff0c;导致大厦将倾的局面&#xff08;也算不上…

RabbitMQ工作模式(5) - 主题模式

概念 主题模式&#xff08;Topic Exchange&#xff09;是 RabbitMQ 中一种灵活且强大的消息传递模式&#xff0c;它允许生产者根据消息的特定属性将消息发送到一个交换机&#xff0c;并且消费者可以根据自己的需求来接收感兴趣的消息。主题交换机根据消息的路由键和绑定队列的路…

RabbitMQ的理论知识点,和使用RabbitMQ时常见的问题点【理论】!

不管使用任何语言调用RabbitMQ 一般都会存在各种问题&#xff0c;我整理了一下 我觉得会遇到的常见问题&#xff0c;并记录了 解决思路 。没有提供具体代码&#xff0c;后续有时间写个代码体会一下&#xff0c;实际有了解决思路&#xff0c;百度里有很多代码让我们使用。哈哈 …

盲人地图使用的革新体验:助力视障人士独立、安全出行

在我们日常生活中&#xff0c;地图导航已经成为不可或缺的出行工具。而对于盲人群体来说&#xff0c;盲人地图使用这一课题的重要性不言而喻&#xff0c;它不仅关乎他们的出行便利性&#xff0c;更是他们追求生活独立与品质的重要一环。 近年来&#xff0c;一款名为蝙蝠…

代码随想录算法训练营第三十八天| 动态规划,509. 斐波那契数,70. 爬楼梯,746. 使用最小花费爬楼梯

目录 动态规划 题目链接&#xff1a; 509. 斐波那契数 思路 代码 题目链接&#xff1a; 70. 爬楼梯 思路 代码 题目链接&#xff1a; 746. 使用最小花费爬楼梯 思路 代码 总结 动态规划 Dynamic programming&#xff0c;DP问题。某一问题包含很多重叠的子问题&#x…

echarts地图叠加百度地图底板实现数据可视化

这里写自定义目录标题 echarts地图叠加百度地图实现数据可视化echarts地图叠加百度地图实现数据可视化 实现数据可视化时,个别情况下需要在地图上实现数据的可视化,echarts加载geojson数据可以实现以地图形式展示数据,例如分层设色或者鼠标hover展示指标值,但如果要将echa…

React 之 组件模块依赖

导入&#xff08;Import&#xff09;和导出&#xff08;exporing&#xff09;组件 在一个文件中声明多个组件&#xff0c;但是文件变得太大的话就不方便查看了。要解决此问题&#xff0c;你可以将一个组件放到一个单独的文件中并&#xff08;导出&#xff09; export 组件&…

运筹系列91:vrp算法包PyVRP

1. 介绍 PyVRP使用HGS&#xff08;hybrid genetic search&#xff09;算法求解VRP类问题。在benchmark上的评测结果如下&#xff0c;看起来还不错&#xff1a; 2. 使用例子 2.1 CVRP COORDS [(456, 320), # location 0 - the depot(228, 0), # location 1(912, 0), …

C++进阶之路——关键字

C进阶——关键字 本系列博客主要对于已经有一定C/C基础的网友&#xff0c;欢迎志同道合的朋友来进行纯粹的技术交流&#xff01;&#xff01;&#xff01; 一、const 在C中&#xff0c;const 关键字是一个非常重要的特性&#xff0c;用于定义变量或对象的值为常量&#xff0c;…

通往AGI路上,DPU将如何构建生成式AI时代的坚实算力基石?

4月19日&#xff0c;在以“重构世界 奔赴未来”为主题的2024中国生成式AI大会上&#xff0c;中科驭数作为DPU新型算力基础设施代表&#xff0c;受邀出席了中国智算中心创新论坛&#xff0c;发表了题为《以网络为中心的AI算力底座构建之路》主题演讲&#xff0c;勾勒出在通往AGI…

Xcode 15构建问题

构建时出现的异常&#xff1a; 解决方式&#xff1a; 将ENABLE_USER_SCRIPT_SANDBOXING设为“no”即可&#xff01;