Android 音视频编解码 -- MediaCodec

news/2025/2/3 16:49:59 标签: android, 视频编解码

引言

如果我们只是简单玩一下音频、视频播放,那么使用 MediaPlayer + SurfaceView 播放就可以了,但如果想加个水印,加点其他特效什么的,那就不行了;

 

学习 Android 自带的硬件码类 – MediaCodec。

 

 

MediaCodec 介绍

 

在Android中是使用MediaCodec类进行编解码。

 

MediaCodec是什么呢?

MediaCodec是Android提供的用于对音视频进行编码(压缩)和解码(解压缩)的类,它通过访问底层的codec来实现编解码的功能。

比如你要把摄像头的视频yuv数据编码为h264/h265,pcm编码为aac,h264/h265解码为yuv,aac解码为pcm等等。MediaCodec是Android 4.1 API16引入的,在Android 5.0 API21加入了异步模式。

 

通常与MediaExtractor, MediaSync, MediaMuxer, MediaCrypto, MediaDrm, Image, Surface, 以及AudioTrack一起使用;

 

数据交换

 

 

 

可以看到,MediaCodec 的数据分为两个部分,从数据的输入编解码后的数据的输出

input : MediaCodec 会通过getInputBuffer(int bufferId) 去拿到一个空的 ByteBuffer , 用来给客户端去填入数据(比如解码,编码的数据),MediaCodec 会用这些数据进行解码/编码处理。


output : MediaCodec 会把解码/编码的数据填充到一个空的 buffer 中,然后把这个填满数据的buffer给到客户端,之后需要释放这个 buffer,MediaCodec 才能继续填充数据。

MediaCodec 内部使用异步的方式对 input 和 output 进行数据处理,MediaCodec 会把 input 的数据处理好给到 output,共用户去渲染;
注意!output 的数据必须释放,不然会影响下一次的数据填充。

 

数据类型
 

编码器共支持3中数据类型:

  • 压缩数据
  • 原始视频数据
  • 原始音频数据

 

这三种数据都是可以通过 ByteBuffer 去处理;但是你可以使用 Surface 去解析原始的视频数据,Surface 使用底层的视频缓冲,而不是映射或拷贝到 ByteBuffer,这样会大大提高编码效率。
但使用 Surface 时,无法访问到原始的视频数据,所以,你可以使用 ImageReader 来访问未加密的解码(原始)数据。在 ByteBuffer 的模式下,你也可以使用 Image 或者 getInput/OutputImage(int) 来获取原始视频帧。

 

编解码的生命周期

 

Stopped,Executing 和 Released

 

Stopped 和 Executing 都有各自的生命周期:

 

  • Stopped:Error、Uninitialized 和 Configured

当调用 MediaCodec 时,此时会处于 Uninitialized 状态,当调用 configure 之后,就会处于 Configured 状态;然后调用 start() 进入 Executing 状态,接着就可以处理数据了。

 

  • Executing:Flushed、Running 和 End of Stream

当调用 start() 就会进入 Executing 下的 Flushed 状态,此时会拿到所有的 buffers,当第一帧数据从 dequeueInoutBuffer 队列流出时,就会进入 Running 状态,大部分时间都在这个状态处理数据,当队列中有 end-of-stream 标志时,就会进入 End of Stream 状态,此时不再接收 input buffer,但是会继续生成 output buffer,直到 output 也接收到 end-of-stream 标志。你可以使用 flush() 重新回到 Flushed 状态。

生命周期图:

 

 

可以使用 stop() 方法回到 Uninitialized 状态;当不再使用 MediaCodec ,还需要使用 release() 去释放该资源。

 

MediaCodec 的主要 API 如下:

getInputBuffers:获取需要编码数据的输入流队列,返回的是一个ByteBuffer数组 ,已弃用
queueInputBuffer:输入流入队列
dequeueInputBuffer:从输入流队列中取数据进行编码操作
getOutputBuffers:获取编解码之后的数据输出流队列,返回的是一个ByteBuffer数组 ,已弃用
dequeueOutputBuffer:从输出队列中取出编码操作之后的数据
releaseOutputBuffer:处理完成,释放ByteBuffer数据

 

使用

 

输入缓冲区

1、手动把数据输入缓冲区 参考下面文章:

Android 音视频编解码(二) -- MediaCodec 解码(同步和异步)_mediacodec config textureview-CSDN博客

2、Surface createInputSurface()  把数据给到surface 就行,surface 自动作为输入缓冲区(简单) 

 

输出缓冲区输出编码后的数据,然后封装 XXX、mp4 文件(封装格式文件)

过程: 原始数据 --->编码 --->压缩数据 ---> x x x.mp4 文件

 

难点: 输入缓冲区 ---> opengl 着色器执行后的数据 ---> surface

这里难点就是 怎么把数据绘制到surface 怎么绘制,以什么样的规则。。。。。。

 

这里就引出EGL。

opengl 着色器执行后的数据 --- 》【EGL】 ----》surface

 

EGL的由来

 OpenGL作为一个图形化API,允许我们操作GPU以绘制图形,但是当涉及到本地的窗口时,就需要一个与平台无关的API来与之进行交互,EGL应运而生,承担起OpenGl和原生窗口系统之间桥梁的作用。

如图:

 

 

EGL 知识点 看该篇:  Android 音视频 --- EGL介绍和使用-CSDN博客

 

 

 

 

 

 

 

 

 

 

 


http://www.niftyadmin.cn/n/5840916.html

相关文章

代码练习2.3

终端输入10个学生成绩&#xff0c;使用冒泡排序对学生成绩从低到高排序 #include <stdio.h>void bubbleSort(int arr[], int n) {for (int i 0; i < n-1; i) {for (int j 0; j < n-i-1; j) {if (arr[j] > arr[j1]) {// 交换 arr[j] 和 arr[j1]int temp arr[…

unity中的动画混合树

为什么需要动画混合树&#xff0c;动画混合树有什么作用&#xff1f; 在Unity中&#xff0c;动画混合树&#xff08;Animation Blend Tree&#xff09;是一种用于管理和混合多个动画状态的工具&#xff0c;包括1D和2D两种类型&#xff0c;以下是其作用及使用必要性的介绍&…

蓝桥杯例题六

奋斗是一种态度&#xff0c;也是一种生活方式。无论我们面对什么样的困难和挑战&#xff0c;只要心怀梦想&#xff0c;坚持不懈地努力&#xff0c;就一定能够迈向成功的道路。每一次失败都是一次宝贵的经验&#xff0c;每一次挫折都是一次锻炼的机会。在困难面前&#xff0c;我…

注解(Annotation)

注解&#xff08;Annotation&#xff09;在 Java 中可以用来简化类的使用&#xff0c;使得被注解的类能够被自动发现、自动创建并在需要的地方直接调用&#xff0c;而不需要手动创建实例。具体来说&#xff0c;注解是用来标识类、方法、字段等的&#xff0c;它们通常与一些框架…

扩散模型(一)

在生成领域&#xff0c;迄今为止有几个主流的模型&#xff0c;分别是 GAN, VAE&#xff0c;Flow 以及 Diffusion 模型。 GAN&#xff1a;GAN 的学习机制是对抗性学习&#xff0c;通过生成器和判别器的对抗博弈来进行学习&#xff0c;这种竞争机制促使生成器不断提升生成能力&a…

基于开源2 + 1链动模式AI智能名片S2B2C商城小程序的内容创作与传播效能探究

摘要&#xff1a;本文围绕开源2 1链动模式AI智能名片S2B2C商城小程序&#xff0c;深入探讨在其应用场景下内容创作与传播效果的关键要素——转发数与转化率。通过剖析如何创作引发用户共鸣、提升用户信任的内容&#xff0c;阐明深度思考内容本质对于实现有效传播的重要性&…

XML DOM 节点信息

nodeName、nodeValue 和 nodeType 属性包含有关节点的信息。 尝试一下 - 实例 下面的实例使用 XML 文件 books.xml。 函数 loadXMLDoc()&#xff0c;位于外部 JavaScript 中&#xff0c;用于加载 XML 文件。 获取元素节点的节点名称 本例使用 nodeName 属性来获取 "book…

Ollama+OpenWebUI部署本地大模型

OllamaOpenWebUI部署本地大模型 前言 Ollama是一个强大且易于使用的本地大模型推理框架&#xff0c;它专注于简化和优化大型语言模型&#xff08;LLMs&#xff09;在本地环境中的部署、管理和推理工作流。可以将Ollama理解为一个大模型推理框架的后端服务。 Ollama Ollama安…