程伟伦,唐恒飞
(201600 上海市 上海工程技术大学)
随着汽车工业稳步发展,汽车电子行业朝着信息化、媒体化方向转变。互联网技术的崛起、智能终端设备的良好应用,人们对于车载多媒体设备的需求急剧增加,高性能的智能终端设备逐渐进入大众视野。智能终端设备搭载流媒体技术可使音频和视频在网络上快速传播并且无需下载等待。在高性能嵌入式设备上搭载流媒体技术,可以实现互联网通讯技术在车载领域的完美应用,研究和设计这样一款集音视频一体化车载媒体播放总成也因此具备了现实意义和科研价值。
在网络流媒体的传输过程中,音频流和视频流常常混合在一起进行传输,这就要求在对流数据进行解封装之后再进行解码操作。本文主要基于开源多媒体处理工具FFmpeg 来实现音视频的编解码工作。FFmpeg 最早由Fabrice Bellard 发起,其支持的常见封装格式有.mp4,.mp3,.flv,.avi 等,支持的常见传输协议有RTSP,RTMP,HTTP,RTP 等。FFmpeg 现如今几乎包含了大部分音视频编码标准,是音视频开发工作者的重要工具。
用户通过点击已经移植到嵌入式设备的Qt界面程序中的下拉按钮,选择想要观看的电台播放频道,系统程序会自动加载rtmp 或rtsp 等网络流媒体地址进行解析并向服务器发起请求,服务器接收到请求后将压缩好的视频文件下发给嵌入式客户端。嵌入式客户端接收到文件压缩包后,音频方面:由FFmpeg 完成一系列解封装、解码、音频重采样后,调用Qt 的QAudioOutput 类播放音频;视频方面:FFmpeg 完成一系列解封装、解码后,利用Qt 自带的OpenGl 完成对视频数据的着色与渲染,再调用自定义的MyVideoCall 完成对视频画面的不间断更新。在音视频同步处理方法方面,分析了3 种方案,选定以音频时间戳为基准,视频向音频靠拢的方案。图1 为整个车载终端音视频功能的系统结构框图。
图1 车载嵌入式流媒体终端的系统结构框图Fig.1 Block diagram of audio and video function system of vehicle terminal
由于嵌入式设备一般都小巧便携,所以,其内存资源往往有限。为了保证编码质量,本文在Windows 操作系统环境中完成软件的编译和运行,实现音视频数据的读取与转换,然后将其移植到嵌入式设备中。图2为媒体文件的解码示意图。FFmpeg 库文件丰富,能够完成解码、编码、转码、封装、解封装、滤波和播放等众多功能。
根据图2 的解码流程图,FFmpeg 对流媒体文件的解码过程可以通过以下几步来详细叙述:
图2 媒体文件的解码流程Fig.2 Decoding flow of media file
(1)初始化库文件。首先通过函数av_register_all(),初始化libavformat 库并注册所有的编码器、解码器和协议。然后需要调用avformat_network_init()函数,初始化网络库。注册成功后,软件就可以rtsp,rtmp,http 协议的流媒体视频。
(2)文件读取模块。avformat_open_input 函数将探测传入的流媒体地址或文件格式,并设置传入参数,打开数据流。
(3)获取视频流信息。avformat_find_stream_info 主要起到了读入数据包(packets)的作用,然后从中提取出流的信息。这个函数不断地更新流信息,而流信息主要是存放在AVStream这个结构体中。而av_dump_format 函数将音视频数据格式通过输出到指定的文件或者控制台,方便了解输入的视音频格式。
(4)查找解码器。获取流信息的过程中会找到解码器的id。
(5)读取数据帧。av_read_frame 函数用于读取具体的音视频帧数据,在完成解码操作之前,需调用av_read_frame()获得视频或音频的压缩数据,对该函数的调用是多次的、频繁的。
音频数据解码出来之后,它的格式一般是不能直接播放的。音频重采样就是将原始的音频数据变换为新的样本格式(sample format)、声道格式(channel)、采样频率(sample rate)以适应不同声音播放的要求。首先,利用swr_alloc()函数创建一个名为SwrContext 的重采样上下文结构体,通过函数swr_alloc_set_opts()函数将所需要的参数填充进SwrContext 结构体中。详细代码段如下并予以说明。
上述代码段中,actx 即为实例化SwrContext结构体,填充完必要的音频参数后通过swr_init()初始化该结构体。最后,利用swr_convert()函数完成每一帧的音频重采样工作。完成重采样后,需释放SwrContext 结构体。完成音频的解码和重采样步骤后,调用Qt 的QAudioOutput 类播放音频即可。
由于FFmpeg 解码的格式默认是yuv 数据,所以解码后要将其转换为RGB 数据,此过程称为转码。本文采用Qt 自带的OpenGL 完成对yuv数据的转码与渲染。OpenGL 是可用于跨平台的应用程序API,其强大功能可绘制小到简单图形大到三维场景等一系列图形界面。OpenGL 完成渲染工作依赖2 个重要的着色器(shader)即顶点着色器与纹理着色器。OpenGL 通过一个名为QGLShaderProgram 的对象来与着色器交互。着色器通过这个对象连接到OpenGL 应用程序中。
OpenGL 视频显示的具体流程可简述如下:使用initializeOpenGLFunctionst()函数初始化OpenGL 函数库;使用QGLShaderProgram 类中的addShaderFromSourceCode 函数将创建的着色器添加进着色器程序中;再调用linkt()使着色器与着色器程序链接在一起;传入已经定义好的顶点坐标与纹理坐标并使之生效;使用glGenTexturest()为yuv 数据开辟纹理内存;通过glBindTexturet()将开辟的纹理内存指向的内容与GL_TEXTURE_2D 绑定,即绑定成二维纹理;利用纹理过滤函数glTexParameterit(),将纹理像素映射成图像像素,此处有多种过滤算法可以选择,使用较多的是线性插值算法和邻近插值算法。
流媒体数据经过解码后便得到了各自独立的数据,所以,音频流和视频流是独自播放的。如何将音视频流完美地流畅地输送到用户的听觉感官与视觉感官,一直以来都是音视频开发问题中的重点。诸如流媒体传输、可视对讲、本地播放等众多领域的厂商都对音视频同步提出了严苛的要求。一旦解码出的音频流和视频流播放同步有偏差,随着时间的推移其异步性将越来越大。
常用的同步策略有:(1)视频同步到音频;(2)音频同步到视频;(3)设置参考时钟,视频和音频以参考时钟为标准。由于人耳对于声音的辨别效果更为敏锐,所以,本文采用第一种同步策略将视频同步到音频上。音视频同步流程如图3 所示。
图3 媒体文件的解码流程Fig.3 Decoding flow of media file
具体软件实现方法是将音频时间戳设为同步时间的参考对象,如果当前视频播放快于同步时间,利用msleep()延迟刷新,反之则加快刷新速率。
软件设计完成后在Win10 操作系统上测试,通过Visual Studio2017运行,运行画面如图4所示。流媒体地址以CCTV-7 军事农业rtmp 地址测试,测试地址为rtmp://58.200.131.2:1935/livetv/cctv7。经过测试,视频播放无花屏且帧数稳定,无明显的延迟或卡顿现象;音频播放流畅,无音频损坏现象;软件启动CPU 占用率低,无内存泄漏现象;视音频同步效果良好,基本符合用户使用要求。
本文的目的在于研究并实现一款适用于车载的流媒体音视频播放终端,为适应相对便携的嵌入式设备而采用FFmpeg 音视频编解码库完成对流媒体数据的解码播放。代码复用性高,运行效果流畅,音频播放完整,视频渲染良好,对嵌入式系统的开发与应用、音视频编解码的处理都有较好的导向与使用价值。