设为首页收藏本站

安徽论坛

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 92423|回复: 0

Android 音视频编解码(一) -- MediaCodec 初探

[复制链接]

76

主题

0

回帖

240

积分

中级会员

Rank: 3Rank: 3

积分
240
发表于 2022-3-26 10:31:50 | 显示全部楼层 |阅读模式
网站内容均来自网络,本站只提供信息平台,如有侵权请联系删除,谢谢!
音视频 系列文章
Android 音视频开发(一) – 使用AudioRecord 录制PCM(录音);AudioTrack播放音频
Android 音视频开发(二) – Camera1 实现预览、拍照功能
Android 音视频开发(三) – Camera2 实现预览、拍照功能
Android 音视频开发(四) – CameraX 实现预览、拍照功能
Android 音视频开发(五) – 使用 MediaExtractor 分离音视频,并使用 MediaMuxer合成新视频(音视频同步)
音视频工程
  前面几章,我们已经学习了音视频开发的一些知识,这几章,我们来学习音视频的编解码;
如果我们只是简单玩一下音频、视频播放,那么使用 MediaPlayer + SurfaceView 播放就可以了,但如果想加个水印,加点其他特效什么的,那就不行了;
所以,这里,先来学习 Android 自带的硬件码类 – MediaCodec。
一. MediaCodec 介绍

MediaCodec 是 从API 16 后引入的处理音视频编解码的类,它可以直接访问 Android 底层的多媒体编解码器,通常与MediaExtractor, MediaSync, MediaMuxer, MediaCrypto, MediaDrm, Image, Surface, 以及AudioTrack一起使用;
1.2 数据交换

接下来,注意看下面这张官方的图,需要好好理解,因为整个流程都是按照这个来的:

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


  • input : MediaCodec 会通过getInputBuffer(int bufferId) 去拿到一个空的 ByteBuffer , 用来给客户端去填入数据(比如解码,编码的数据),MediaCodec 会用这些数据进行解码/编码处理
  • output : MediaCodec 会把解码/编码的数据填充到一个空的 buffer 中,然后把这个填满数据的buffer给到客户端,之后需要释放这个 buffer,MediaCodec 才能继续填充数据。
   MediaCodec 内部使用异步的方式对 input 和 output 进行数据处理,MediaCodec 会把 input 的数据处理好给到 output,共用户去渲染;
注意!output 的数据必须释放,不然会影响下一次的数据填充。
  1.3 数据类型

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


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

它的生命周期可以分为三个: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() 去释放该资源。
请一定要理解上面两张图,因为后面的编解码都是基于上面的流程的!!
有时候编解码器会遇到错误并处于错误状态,此时会通过排队操作的无效返回值或有时通过异常来传达的。
调用reset()使编解码器再次可用,调用它可以从任何状态回到初始化状态,否则就调用 release() 来移动到终端的 release 状态。
关于MediaCodec 的编解码流程,我们等到下一章再学习。
MediaCodec 的主要 API 如下:


  • getInputBuffers:获取需要编码数据的输入流队列,返回的是一个ByteBuffer数组 ,已弃用
  • queueInputBuffer:输入流入队列
  • dequeueInputBuffer:从输入流队列中取数据进行编码操作
  • getOutputBuffers:获取编解码之后的数据输出流队列,返回的是一个ByteBuffer数组 ,已弃用
  • dequeueOutputBuffer:从输出队列中取出编码操作之后的数据
  • releaseOutputBuffer:处理完成,释放ByteBuffer数据
下一章,一起学习MediaCodec 的解码
Android 音视频编解码(二) – MediaCodec 解码(同步和异步)
参考:
https://developer.android.com/reference/android/media/MediaCodec
https://www.cnblogs.com/renhui/p/7478527.html

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
免责声明
1. 本论坛所提供的信息均来自网络,本网站只提供平台服务,所有账号发表的言论与本网站无关。
2. 其他单位或个人在使用、转载或引用本文时,必须事先获得该帖子作者和本人的同意。
3. 本帖部分内容转载自其他媒体,但并不代表本人赞同其观点和对其真实性负责。
4. 如有侵权,请立即联系,本网站将及时删除相关内容。
懒得打字嘛,点击右侧快捷回复 【右侧内容,后台自定义】
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

快速回复 返回顶部 返回列表