业界动态流媒体开发 规范及协议 技术方案 应用方案 大杂烩
返回首页

EMIPLIB使用入门

落鹤生 发布于 2010-09-08 10:49 点击:次  来自:CSDN博客
基本上这个库的目的就是要完成一个多媒体的网络传输库,方便多种媒体在网络上进行传输。从上面可以看到,它提供了从底层的数据采集、编码解码、传输等功能。我是在window下做一个开发,对于音频它使用了winmm.lib库,对于视频使用了Dshow以及QT for windows。
TAG: speex  VoIP  JRTP  EMIPLIB  

mwg_arden 的草稿,转载需注明。这个库遵守LGPS,所以文档也遵守。

 EMIPLIB(http://research.edm.uhasselt.be/emiplib)的全称是'EDM Media over IP libray' 。EDM是Hasselt University大学的Expertise Centre for Digital Media  ,这个库就是这里开发的。

 这个库能做什么呢?官方是这么描述的(版本0.14.0):

  • Soundcard input (using OSS, WinMM and Jack)
  • Soundcard output (using OSS, ALSA, ESD, WinMM, Jack and SDL)
  • WAV file input (using libsndfile, libaudiofile or a simple internal WAV reader)
  • WAV file output (using libsndfile or a simple internal WAV writer (8 bit, mono))
  • Webcam input (using Video4Linux and DirectShow)
  • Speex compression
  • U-law audio encoding
  • H.263+ compression (using libavcodec)
  • Mixing of incoming audio streams
  • Synchronization of RTP streams based on RTCP information
  • 3D sound effects using HRIR/HRTF data from the LISTEN project
  • Easy to use voice over IP (VoIP) and video over IP sessions

 基本上这个库的目的就是要完成一个多媒体的网络传输库,方便多种媒体在网络上进行传输。从上面可以看到,它提供了从底层的数据采集、编码解码、传输等功能。当然,它不是独立的,比如,我是在window下做一个开发,对于音频它使用了winmm.lib库,对于视频使用了Dshow以及QT for windows。 另外,它也依赖于下面两个库:jrtplib以及jthread。比较详细的可以到官方网站找到参考。http://research.edm.uhasselt.be/emiplib/documentation/index.html

 下面我们就针对windows平台下展开吧,因为我的EMIPLIB经验基本上是在windows平台地...

 第一步:编译库(最基本编译)

 先说说我的平台及环境:windows xp sp2 , vc8(第一次使用这个新的IDE,因为这个lib只提供了VC8的项目文件,时间原因我没办法尝试mingw及vc6等)。

 可以到下面地址下载到源代码:

EMIPLIB   http://research.edm.uhasselt.be/emiplib/emiplib-0.14.0.zip

JTHREAD  http://research.edm.uhasselt.be/jori/jthread/jthread-1.2.1.zip      

JRTPLIB   http://research.edm.uhasselt.be/jori/jrtplib/jrtplib-3.7.0.zip

 下载完以后,开始编译JTHREAD,用vc8打开源代码中的sln文件,在项目设置中C++项目下代码生成中选择多线程调试(/Mtd)。以同样方法编译JRTPLIB。

这两个库使用vc6和vc8都可以很轻松的编译,需要注意的是生成静态库时候要统一代码生成中的选项,我这里使用了/Mtd。完成后,在你的debug或者release目录线面会有这两个库:JRTPLIB.LIB JTHREAD.lib。如果编译这两个库的时候有问题,可以给我mail,或者直接去mail到作者那里,之前我也问过他一些问题,他是个不错的人。

 然后我们需要来编译最大个的EMIPLIB库了,在EMIPLIB的源代码目录有README文件,上面有在windows下编译此库的参考。比较麻烦的问题是对于视频,我们可能需要添加QT支持(这可能需要我们在windows下先安装好QT,并自己手动完成一些文件)。对于最基本的编译我们先不去管它。上面的README文件中也说明了,在源代码目录的src\core\目录下面有一个配置文件mipconfig_win.h,我们可以在编译前进行一些选择,来得到更多功能支持的库。不过现在我们只使用默认的,只有speex支持被添加了。

 用vc8打开sln文件吧,要正确的进行编译,我们最好先把上面需要的两个库,以及一些头文件放在一个合适的地方,让IDE可以找到它们。这需要你设置vc的目录(在工具--选项里面)添加include目录及lib目录。然后也在项目设置中设定多线程调试(/Mtd),现在应该可以编译EMIPLIB了。(PS:我们可能需要安装Dshow,新的版本MS 已经把它从DxSDK中踢出来鸟,放到了PlatFormSDK 中)。

 最基本的编译应该不会花去我们太多时间。让我们先尝尝鲜,看看怎么用这个库。

 第二步:hello world

 在EMIPLIB源代码目录里面有一个examples目录,里面给了几个例子。我们找一个功能比较全的叫做feedbackexample.cpp,来看看怎么使用这个库:

我们省略了其中一些代码,只贴出来比较重要的。

  1. /* 这个demo它打开一个叫做soundfile.wav的文件,并对其进行采样、uLaw编码、
  2. RTP编码然后设定好RTP的目的地(这里它发送给了自己),再经过RTP解码、uLAW解
  3. 码、采样编码,发给声卡让它播放出来。 */ 
  4.  
  5.  MIPTime interval(0.020); //设定间隔为20ms 
  6.  MIPAverageTimer timer(interval); //设定计时器          
  7.  MIPWAVInput sndFileInput;  //声音文件输入 
  8.  MIPSamplingRateConverter sampConv, sampConv2;    //采样转换 
  9.  MIPSampleEncoder sampEnc, sampEnc2, sampEnc3;   //采样编码 
  10.  MIPULawEncoder uLawEnc; //uLaw编码 
  11.  MIPRTPULawEncoder rtpEnc; //rtp编码 
  12.  MIPRTPComponent rtpComp; //rtp组建   
  13.  MIPRTPDecoder rtpDec; //rtp解码 
  14.  MIPRTPULawDecoder rtpULawDec;  //rtp ulaw解码 
  15.  MIPULawDecoder uLawDec; //uLaw解码                                   
  16.  MIPAudioMixer mixer;   //混音 
  17.  MIPWinMMOutput sndCardOutput; //声卡输出 
  18.  MyChain chain("Sound file player");//链:用来把上面组建串起来的对象。  
  19.  RTPSession rtpSession;//RTP会话,来自jrtplib  
  20.  bool returnValue;//返回值   
  21.  
  22.  int samplingRate = 8000;//采样率默认为8kHz  
  23.  int numChannels = 1;//声道设置默认为单声道 
  24.  
  25.  //打开一个wav文件。 
  26.  returnValue = sndFileInput.open("soundfile.wav", interval); 
  27.  
  28. //初始化采样转换,设置了采样率以及声道             
  29.  returnValue = sampConv.init(samplingRate, numChannels); 
  30.  
  31. //初始化采样编码,参数用于设定音频数据在计算机中的保存形式 
  32.  returnValue = sampEnc.init(MIPRAWAUDIOMESSAGE_TYPE_S16); 
  33.  
  34. //初始化ulaw编码 
  35.  returnValue = uLawEnc.init(); 
  36.  
  37. //初始化rtp编码,这个组建可以创建发送到RTP组件的RTP消息。  
  38. returnValue = rtpEnc.init(); 
  39.  
  40. //初始化RTPSession,需要设置包括端口采样率等等与传输有关的参数 
  41.  RTPUDPv4TransmissionParams transmissionParams; 
  42.  RTPSessionParams sessionParams; 
  43.  int portBase = 60000; 
  44.  int status; 
  45.  
  46.  transmissionParams.SetPortbase(portBase); 
  47.  sessionParams.SetOwnTimestampUnit(1.0/((double)samplingRate)); 
  48.  sessionParams.SetMaximumPacketSize(64000); 
  49.  sessionParams.SetAcceptOwnPackets(true); 
  50.  //建立一个RTPSession 
  51.  status = rtpSession.Create(sessionParams,&transmissionParams); 
  52.  
  53.  //添加一个目的地,RTPSession将往此目的发送RTP数据。这里我们发送给自己。 
  54.  status = rtpSession.AddDestination(RTPIPv4Address(ntohl(inet_addr("127.0.0.1")),portBase)); 
  55.  
  56.  //初始化RTP组件,使用我们刚才定义的RTPSession为参数 
  57.  returnValue = rtpComp.init(&rtpSession); 
  58.  //初始化RTP解码器 
  59.  returnValue = rtpDec.init(true, 0, &rtpSession); 
  60.  //设置RTP解码器使用ulaw规则 
  61.  
  62.  returnValue = rtpDec.setPacketDecoder(0,&rtpULawDec); 
  63.  // 初始化ulaw解码,转换 被U-law 解码的采样数据为线性解码采样 
  64.  returnValue = uLawDec.init(); 
  65.  
  66.  // 初始化采样编码,转换接受到的音频数据为浮点数形式存储 
  67.  
  68.  returnValue = sampEnc2.init(MIPRAWAUDIOMESSAGE_TYPE_FLOAT); 
  69.  
  70.  //初始化采样转换,设置参数采样率及声道 
  71.  returnValue = sampConv2.init(samplingRate, numChannels); 
  72. //初始化混音 
  73.  
  74.  returnValue = mixer.init(samplingRate, numChannels, interval); 
  75. //初始化声卡输出 
  76.  returnValue = sndCardOutput.open(samplingRate, numChannels, interval); 
  77. //声卡输出使用的数据形式 
  78.  
  79.  returnValue = sampEnc3.init(MIPRAWAUDIOMESSAGE_TYPE_S16LE); 
  80.  
  81.  // 建立整个链:看看这个顺序,这是整个程序工作的逻辑 
  82.  returnValue = chain.setChainStart(&timer); 
  83.  returnValue = chain.addConnection(&timer, &sndFileInput); 
  84.  returnValue = chain.addConnection(&sndFileInput, &sampConv); 
  85.  returnValue = chain.addConnection(&sampConv, &sampEnc); 
  86.  returnValue = chain.addConnection(&sampEnc, &uLawEnc); 
  87.  returnValue = chain.addConnection(&uLawEnc, &rtpEnc); 
  88.  returnValue = chain.addConnection(&rtpEnc, &rtpComp); 
  89.  returnValue = chain.addConnection(&rtpComp, &rtpDec); 
  90.  returnValue = chain.addConnection(&rtpDec, &uLawDec, true); 
  91.  returnValue = chain.addConnection(&uLawDec, &sampEnc2, true); 
  92.  returnValue = chain.addConnection(&sampEnc2, &sampConv2, true); 
  93.  returnValue = chain.addConnection(&sampConv2, &mixer, true); 
  94.  returnValue = chain.addConnection(&mixer, &sampEnc3); 
  95.  returnValue = chain.addConnection(&sampEnc3, &sndCardOutput); 
  96.   
  97.  //启动这个链 
  98.  returnValue = chain.start(); 
  99.  
  100.  //这里添加等待停止的代码 
  101.  //停止  
  102.  returnValue = chain.stop(); 
  103.  rtpSession.Destroy(); 

要想运行这个程序,需要我们的编译器可以找到jrtplib.lib,jrtplib.lib,emiplib.lib 以及 这些lib导出符号需要的一些.H文件。比较好的方法是,把它们分别放到相应目录中,在vc目录中设置。另外,还需要在lib中添加 ws2_32.lib, winmm.lib 。运行时库选项统一为"/MTd" 。其它的问题,可能还需要你在忽略库列表中把一些冲突的库加上,比如libc.lib、libcmt.lib、msvcrt.lib、libcd.lib、msvcrtd.lib ...

 源代码中没有给你提供上面所说的那个wav文件,你需要自己找一个。

 能听到那个XXX.wav的声音了,大功告成。 

 第三步:一些介绍

 我们来大体了解一下EMIPLIB,以及怎么使用它。

为了提供一个灵活性比较好的框架,此库德目的是建立一些列相关的小组件,每个组件提供一些特定的工作,如音频取样,写音频到文件或者传输音频包等等。这些组件可以放置到一个chain(链)中,在这个链上,这些组件可以相互通信。这样,(按照需求)通过连接这些组件到一条链上,可以建立复杂的引用程序。

 另外,EMIPLIB为了大家使用方便也提供了一些更高级的类,它们包装好了一些常用的功能,给我们更好的interface。比如上面hello world中的那一串的定义,初始化,貌似都差不多的chain,MIPAudioSession类都给我们包装好了。如果这些功能已经提供了足够的功能,使用它们就好了,如果你有特殊的要求,你也可以像上面例子一样,自己写那一堆组件,按照你的思路让他们工作。

 大部分可以放到 MIPComponentChain上的组件都派生自MIPComponent类。我们需要作的工作就是从这些派生类里面选择合适的组件,把它们放在一个chain上面,它就可以开始工作了。即使不使用EMIPLIB提供给我们的包装类,这些工作也不会很繁琐。比较详细的描述,大家可以参考EMIPLIB主页上的 (arden1019)

本站文章除注明转载外,均为本站原创或编译欢迎任何形式的转载,但请务必注明出处,尊重他人劳动,同学习共成长。转载请注明:文章转载自:罗索实验室 [http://www.rosoo.net/a/201009/10112.html]
顶一下
(2)
100%
踩一下
(0)
0%
------分隔线----------------------------
发表评论
请自觉遵守互联网相关的政策法规,严禁发布色情、暴力、反动的言论。
评价:
表情:
用户名: 验证码:点击我更换图片
推荐内容