EMIPLIB全称为“EDM Media over IP Library”,是比利时哈瑟尔大学下属研究机构Expertise Centre for Digital Media (EDM)研发的开源代码,此库用于串联流媒体系统所必须的各个功能模块:音视频数据采集(Input)与播放(Output)、编码(Encode)与解码(Decode)、网络传输(Transmission),使流媒体系统的开发变得更加容易与高效。
此库的框架设计合理,功能强大,尤其便于二次开发。下面将分别从它的主要功能部件、运行机制及原理实现进行简要介绍和分析。
目前EMIPLIB支持的具体功能如下:
l 声卡输入:支持OSS,WinMM,Jack和PortAudio;
l 声卡输出:支持OSS,ALSA,ESD,WinMM,Jack,SDL和PortAudio;
l 支持OpenAL输出组件;
l 支持WAV格式文件输入,但需要预装libsndfile、libaudiofile或者一个WAV reader作为支持库;
l 支持WAV格式输出,但需要预装libsndfile或者一个WAV writer作为支持库;
l 支持摄像头、并口或者USB输入:需要预装Vide04Linux和DirectShow组件;
l 支持Speex压缩方式;
l 支持U-law音频编码标准;
l 支持A-law音频编码标准;
l 支持LPC压缩方式;
l 支持GSM 06.10压缩方式;
l 支持H.263+压缩方式;
l 支持针对音频流的混音处理;
l 能够根据RTCP报文信息同步RTP码流;
l 支持通过HRIR/HRTF信息实现3D特效;
l 能便捷的辅助实现VOIP(Voice Over IP)和网络视频会话。
EMIPLIB已经在下列平台上通过了测试:
l GNU/Linux
l Mac OS X
l Win32
l WinCE
l Android
一个通用的流媒体系统必须至少包含如下组件:
通用流媒体系统结构图
(1) 输入模块(Input Module)
获取原始视频流,可以是从文件中读取,也可以通过设备采集获得。
(2) 编码模块(Encode Module)
按照各种编解码协议,将原始视频流进行压缩,使传输速率和质量得到提高,适用于网络传输。
(3) 网络传输模块(Transmission Module)
根据所使用的网络传输协议,将压缩后的视频码流打包为相应报文形式,便于实现对应协议中的流量控制、差错控制等控制行为。
(4) 解码模块(Decode Module)
将被压缩的视频流还原为原始视频流。
(5) 输出模块(Output Module)
将原始视频流进行播放或者存储。
上述每一个模块都可以根据实际需求,采用不同的实现手段。比如编码模块,既可以使用高性能的H.264编码方式压缩数据流,也可以在某些低码流应用场景中选择H.263作为实现手段。
因此,EMIPLIB根据上述特点,将自己设计为一个可供拆卸的逻辑“货架”,功能模块中每一种特定的需求实现就是可在“货架”中安置的“货物”。我们将所需要的“货物”按照一定的实现顺序依次安放在货架上,当视频流从“货架”头流动到“货架”尾时,就能获取到我们需要的数据。
举个例子,当我们需要在一个已安装V4L的Linux系统上把摄像头中捕获到原始数据流(假设格式为YUV420P)压缩为H.264编码后,打包为RTP包格式传送给客户端,那么我们应该依次把“V4L调用组件”、“H264压缩组件”、“RTP打包组件”这些“货物”放入货架上。当我们启动货架开关后,在货架尾部就可以得到所期望的RTP码流。
EMIPLIB将把货物依次串起来的“货架”叫做Component Chain(组件链),把“货物”叫做Component(组件)。EMIPLIB使用一个虚拟类MIPComponent定义作为“货物”所必须具备的功能,供外部调用,而每一个真正负责实现该功能模块的类对象必须继承该标准接口,通过不同的底层手段,来实现相同的接口定义功能。
因此,根据EMIPLIB开发出的流媒体系统,模块间松耦合,各模块开发过程比较独立,后期可扩展性和可伸缩性都很好。流媒体系统的搭建只需要为每个功能模块选择合适自身系统特点的实现组件,使用一条Component Chain(组件链)将每个组件串起来,视频流就将源源不断的从第一个功能模块流向最后一个功能模块,并按照我们期望的方式输出数据。
至于EMIPLIB的跨平台支持性,在一定程度上是依靠CMake自动化建构系统的辅助实现的。CMake使用与Make相似的build process方式,只是 CMake 的build文档取名为 CmakeLists.txt。Cmake 并不直接建构出最终的软件,而是产生标准的建构档(如 Linux系统下产生Makefile或 Windows Visual C++ 环境下产生projects/workspaces),然后再依靠一般的建构方式使用。同时,CMake可以获取当前操作系统环境的具体配置,整理出可供EMIPLIB调用的库资源,并按照EMIPLIB预写入的软件配置方案(.ini文件),将系统已安装的库资源以宏定义的形式写入到配置文件。当EMIPLIB运行时,则可通过读取该配置文件中的宏定义,获取当前系统配置信息,从而针对不同系统环境进行区别处理。
1. EMIPLIB的功能模块划分
为了实现我们在3.2.4.1节提到的功能,EMIPLIB将自身已经实现的所有组件分为八个功能模块,具体如下:
三 ‑ 2 功能模块结构图
l 输入(Input):
从音频文件输入:mipaudiofileinput
Android平台的音频调用:mipaudiorecorderinput
Windows平台下一般采用DirectShow进行视频采集:mipdirectshowcapture
自实现的特定频率的音频产生器,实现简单,通过输入的左/右声道的振幅和频率、采样速率、采样周期,带入音频运算式中即可获得所需音频数据:mipfrequencygenerator
Linux下的Jack声音框架(Jack audio connection kit):mipjackinput
从文件中读取音频码流,基于libsndfile库:mipsndfileinput
V4L(video for linux)是Linux下视频采集设备驱动程序的编写提供统一的接口而提出的一套规范(API):mipv4linput
V4L2(video for linux Two),对V4L做出极大改进,因此与V4L并不兼容:mipv4l2input
WAV音频文件输入:mipwavinput
Windows下音频采集方案WINMM:mipwinmminput
以原始码流格式YUV420P存储的文件读入:mipyuv420fileinput
l 编解码(Codec):
A律编解码组件:mipalawdecoder,mipalawencoder
需FFMPEG中libavcodec库支持,EMIPLIB针对视频部分仅实现H.263+编解码工作,因此视频部分的RTP打包也仅实现荷载为H.263+编码格式报文:mipavcodecdecoder,mipavcodecencoder
GSM 06.10编解码组件:mipgsmdecoder,mipgsmencoder
LPC编解码组件:miplpcdecoder,miplpcencoder
SILK编解码组件:mipsilkdecoder,mipsilkencoder
Speex编解码组件:mipspeexdecoder,mipspeexencoder
基于Tiny JPEG Decoder 库,支持将JPEG压缩格式逐帧转换为YUV420P原始数据流:miptinyjpegdecoder
u律编解码组件:mipulawdecoder,mipulawencoder
l 网络传输(Transmission):实现RTP协议针对不同编码格式的打包和解包工作
(1) EMIPLIB对音频压缩格式的RTP打包、解包支持:
A律、u律、GSM、L16(处理16bit按照大端存储方式数据流,默认采样率为44100Hz,作为RFC3551中预定义的负载类型实现)、LPC、Dummy解包机制(当收到不支持的打包格式时,使用此机制抛弃报文。而不会作为异常抛出)、SILK、Speex
(2) EMIPLIB对视频压缩格式的RTP打包、解包支持:
按照RFC实现了H.263+格式的打包、解包。
内部实现(非RFC实现)H.263+与YUV420P的RTP打包,但外部设备无法识别。
l 格式转换(Transform):
mipaudiofilter
mipaudiosplitter
mipavcodecframeconverter
miphrirbase
miphrirlisten
mipsampleencoder
mipsamplingrateconverter
mipspeexechocanceller
mipyuv420framecutter
l 计时器(Timer):作为Component Chain的第一个组件,按照码流速率将视频流按帧分时处理
组件链中每隔设定时间,发送MIPSYSTEMMESSAGE_ISTIME系统报文触发下一组件:mipaveragetimer
多线程组件链时,设定组件间时序关系:mipinterchaintimer
等待特定事件完成后才开启计时器(比如一个被动等待声音输入的声卡设备在组件链顶端,则可以将此定时器放在其后,当有音频数据输入后系统才开始运行):mippusheventtimer
l 输出(Output):
Linux系统环境下调用Advanced Linux Sound Architecture (ALSA) 来实现声卡输出:mipalsaoutput
Android平台上音频回放机制:mipaudiotrackoutput
Enlightened Sound Daemon (ESD)声卡输出:mipesdoutput
Jack音频输出套件:mipjackoutput
OpenAL音频输出组件:mipopenaloutput
QT播放器(调用其API可直接播放音视频数据流):mipqtoutput
SDL音频输出组件,接受16 bit本地原始音频流的播放:mipsdlaudiooutput
将收到的音频数据流写入本地文件:mipsndfileoutput
支持将格式为YUV420P的视频流进行本地存储:mipvideoframestorage
仅支持将8 bit无符号音频流写入本地文件:mipwavoutput
Win32/WinCE平台下的音频播放组件:mipwinmmoutput
l 混音(Mixer):
mipaudiomixer
mipmediabuffer
mipvideomixer
l 输入输出(IO,InputOutput):既可以在组件中作为Input组件使用,也可以作为Output组件使用
调用OSS(Open Sound System开放声音系统):mipossinputoutput
调用PortAudio声卡:mippainputoutput