十分钟学会如何开发一个音频播放器(ffmpeg3.2+SDL2.0)
前言
这套教程是使用ffmpeg3.2+SDL2.0开发的。这两个版本跟之前版本的函数有了很大的改变,但基本的原理还是一致的。在阅读时请注意自身使用的版本。本篇的源码已提交在github上:https://github.com/XP-online/audio-player
媒体播放器的原理
媒体播放器的播放原理很简单:一个媒体文件文件如mp4,mp3等内部储存着几个AV流,一般包含视频流,音频流有的还有字幕流等。而每个流里都是有若干个包(packet)组成的。包中储存的就是最重要的信息“帧”(frame),帧中储存的数据就是我们需要的视频或音频等的原始数据。
不过包(packet)内的信息被编码过了,所以播放器需要找到这些包并解编码出每一帧,将这些帧中的数据或传给操作系统播放出来(如音频播放就是通过操作系统播放的)或者按照我们自己的方式处理(如视频信息我们可以在获得每一帧的图像信息后,通过任何我们想要的方式显示)。
创建一个音频播放器的步骤
本篇我们先说一下创建一个音频播放器的步骤。在这里我们有必要在强调一下音频播放的原理即:找到音频流 —— 读取音频流中的包 —— 解编码包并获取音频帧 —— 将音频帧的数据给操作系统让操作系统将音频播放出来。那么我们的具体操作步骤如下所示:
- 读取AV文件格式信息和音频或视频流的索引( avformat_open_input ,avformat_find_stream_info )。
- 找到解码器,并设置解码器参数( avcodec_find_decoder ,avcodec_parameters_to_context ,avcodec_open2 )以及sdl的重采样相关参数。
- 循环调用 av_read_frame 不断从音频流里读取packet。
- 使用 avcodec_send_packet 和 avcodec_receive_frame 相配合不断地将packet送入解码器,并从解码器中读取解码后的frame。
- 对解码后的frame的采样率进行转换( swr_convert )。
- 在sdl的回调中将设置好的数据放入系统指定的地址中。系统将根据传入的数据播放声音( sdl_audio_callback )。
源码分析
在这里的代码主要是为了便于理解音频播放的原理。设计时的代码逻辑,变量位置,类型也是基于这一个目的设计的。大家完全可以在看懂了之后按照自己的方式设计代码逻辑。
一、定义一些基本的参数
这里定义一些全局变量。每个变量的意义后面有注释,具体的用法下文会提到。
#define MAX_AUDIO_FRAME_SIZE 192000 // 1 second of 48khz 32bit audio
//swr
struct SwrContext* au_convert_ctx; // 重采样上下文
int out_buffer_size; // 重采样后的缓冲区
uint8_t* out_buffer; // sdl调用音频数据的缓冲区
//audio decode
int au_st