FFmpeg入门(三):使用SDL播放音频流

under Qt  tag FFmpeg    Published on May 17th , 2020 at 08:03 am

一、前言

前面介绍了使用FFmpeg播放视频流,但是有个问题还没有解决,就是播放音频流。本文将会写一个Demo让FFmpeg和SDL2配合工作,播放音频。

二、选择SDL的原因

0.Windows下播放音频的方案

  1. 直接调用系统API的wavein、waveout等函数
  2. 使用directsound播放

这两个方案都比较难用,不推荐

1.当下比较流行的播放音频库

  1. OpenAL:强大,跨平台,资料相对比较少。LGPL;
  2. PortAudio:接口简单,方便获取设备,播放音频。GPL,
  3. SDL:很有名的跨平台库
  4. SDL_audioin

其中OpenAL、ProtAudio和SDL这三个库 我都有用过,觉得还是SDL比较好用,因此我们使用SDL来播放音频。

2.采用SDL的原因

SDL本身是一个多媒体库,其最强大的地方不是在音频上,而是在图形图形上。

那么,为何我们前面不使用SDL显示视频呢?

将SDL嵌入我们的窗体之后,窗体上方的控件样式会失效(比如QSS样式),这就意味着,放在窗体上方的按钮或者其他控件不能够透明。而我们的播放器当然需要在播放界面上放一个带透明度的控制栏啦。而且目前也找不到好的解决方法,无奈之下,只好将图像显示改成直接用绘图的方法绘制在控件上。当然了,直接绘制的方法在效率上也不会差。因此就这么干了。

三、使用SDL2

0.下载SDL

SDL官网地址:http://www.libsdl.org/

我们现在都是在Windows系统下使用,因此直接下载编译好的版本就行了。

基本上的库Windows的版本都有提供已经编译好的版本,SDL也是如此:

我们用的是mingw的编译器,因此选择下载mingw的版本。

1.引用SDL2

首先新建一个Qt工程,然后引用FFmpeg和SDL2.关于FFmpeg的引用之前已经介绍过,这边不再重复。

SDL下载完成后,首先将LIB库解压出来。根据情况选择x86_64-w64-mingw32内的库

选择include和lib 这2个文件夹。拷贝到Qt目录下的SDL2文件夹(自己新建)

我删除了这两个文件夹下没用的子目录,具体如下

将SDL2拷贝到工程目录下,在工程的pro文件中加入:

INCLUDEPATH += $$PWD/SDL2
include ($$PWD/SDL2/sdl2.pri)

SDL2文件夹下新建sdl2.pri,并加入以下代码

INCLUDEPATH += $$PWD/include

LIBS += $$PWD/lib/libSDL2.a

2.编写代码

加入SDL的头文件之后,编译的时候会提示main函数没有定义

原因是 SDL_main.h中有如下一段话:

#if defined(SDL_MAIN_NEEDED) || defined(SDL_MAIN_AVAILABLE)
#define main    SDL_main
#endif

可以看出这里已经定义了一个main了,因此我们写的程序中的main便不能生效了,解决方法:

在我们自己写的main函数的前面加上:

#undef main
int main(int argc, char* argv[])
{
    ...
}

FFMPEG读取音频文件和解码音频的代码,不做介绍了,基本上和前面视频的操作类似。

这里需要注意的一点是:

SDL播放音频是通过回调函数的方式播放,且这个回调函数是在新的线程中运行,此回调函数固定时间激发一次,这个时间和要播放的音频频率有关系。

因此我们用FFMPEG读到一帧音频后,不是急着解码,而是将数据存入一个队列,等SDL回调函数激发的时候,从这个队列中取出数据,然后解码 播放。

代码这里不做介绍了,直接上完整的工程吧。

四、完整工程

注:

本工程播放AAC文件是正常的,AAC文件已经放入工程中了。

但是在播放mp3的时候不正常,都是杂音,原因是因为audio_decode_frame这个函数中解码音频后处理的不当,暂时先不管,在后面的视频播放器中,已经修正这个问题。


本文由simyng创作, 采用知识共享署名4.0 国际许可协议进行许可,转载前请务必署名
  文章最后更新时间为:May 16th , 2020 at 04:27 pm