该文章首发于微信公众号:字节流动

FFmpeg 开发系列连载:


字节流动:FFmpeg 开发(01):FFmpeg 编译和集成zhuanlan.zhihu.com


ffmpeg音频倒放 ios开发 ffmpeg播放pcm_ffmpeg从入门到精通pdf网盘


字节流动:FFmpeg 开发(02):FFmpeg + ANativeWindow 实现视频解码播放zhuanlan.zhihu.com

ffmpeg音频倒放 ios开发 ffmpeg播放pcm_ffmpeg从入门到精通pdf网盘_02

字节流动:FFmpeg 开发(03):FFmpeg + OpenSLES 实现音频解码播放zhuanlan.zhihu.com


ffmpeg音频倒放 ios开发 ffmpeg播放pcm_ffmpeg从入门到精通pdf网盘_03


本文基于上一篇文章 FFmpeg + OpenSLES 实现音频解码播放 ,利用 FFmpeg 对一个 Mp4 文件的音频流进行解码,然后将解码后的 PCM 音频数据进行重采样,最后利用 OpenSLES 进行播放的同时,将 PCM 音频一个通道的数据实时渲染成柱状图。


ffmpeg音频倒放 ios开发 ffmpeg播放pcm_ffmpeg音频倒放 ios开发_04


关于音频的可视化,在旧文中,我们曾经实现过将 Android AudioRecorder 采集的实时音频单通道 PCM 数据用 OpenGL 渲染成柱状图。具体的渲染过程和细节,请移步这篇文章,代码已开源:

OpenGL ES 实现可视化实时音频

提取一个通道的音频数据

在上一篇文章,我们构建 OpenSLES 播放器时,对数据格式的定义如下:


SLDataFormat_PCM


从上面代码中可以看出,音频驱动接收的 PCM 数据的采样率是 44.1kHz,双通道,采样大小 2 字节。由于我们要渲染的是一个通道的 PCM 数据,所以需要对双通道的数据做一个提取。


ffmpeg音频倒放 ios开发 ffmpeg播放pcm_ffmpeg从入门到精通pdf网盘_05


如上图所示,解码后的 PCM 数据是 2 个通道的数据交叉存储,当使用指针偏移提取某一通道的数据时,每次偏移的步长是 2 字节 X 通道数 = 4 个字节。

提取某一通道的 PCM 数据方式如下,通过该方式我们可以将一帧音频数据每个通道的数据进行分离。


//小端序存储的音频数据


另外需要注意的是,数据的存储方式分为大端序和小端序,小端序指低地址存放低位、高地址存放高位,大端序与小端序相反,即低地址存放高位,分离通道数据需要注意。


//大端序存储的音频数据


OpenGL ES 渲染音频数据

OpenGLES 全称 OpenGL for Embedded Systems ,是三维图形应用程序接口 OpenGL 的子集,本质上是一个跨编程语言、跨平台的编程接口规范,主要应用于嵌入式设备,如手机、平板等。

由于前期已经系统地阐述了 OpenGL ES 相关知识点,这里就不做展开叙述,详细内容请参考:

Android OpenGL ES 从入门到精通系统性学习教程

利用 OpenGL 渲染音频数据,本质上就是根据音频数据的值去构建一组如下图所示的网格,最终渲染成条状图。


ffmpeg音频倒放 ios开发 ffmpeg播放pcm_ffmpeg从入门到精通_06


接下来就是代码实现过程,首先在 Java 层创建 GLSurfaceView 的 Render ,FFMediaPlayer 中增加对应 Native 函数:


private


对应 Java 层接口的 JNI :


//可视化音频的渲染接口


Native 层实现音频渲染的类:


#include


最后只需要在 OpenSLES 播放器的回调函数(见上篇文章)中调用下面函数即可:


AudioFrame