JRTPLIB@Conference DIY视频会议系统

61 篇文章 0 订阅
29 篇文章 0 订阅

------------------------------------------------------------------------------------------------------------------------------

JRTPLIB@Conference DIY视频会议系统 一、开编  

      前段时间一直在研究视频相关的东西。也有了一定的成果,包括MPEG流媒体服务器代码(当然了,是实验而已,当中的RTP也是手工写的,没有RTCP)和H263@S3C2410系列(打算在S3C2410上进行视频的H263采集、压缩、解压缩和显示)。收到了一些读者的来信,我也很高兴,但要声明的是我从做的行业与视频无关,有时候我对一些问题也是无能为力,我也只是因为感兴趣玩玩而已。下面谈谈JRTPLIB@Conference这个系列的情况。
      当时写MPEG流媒体服务器时,到网上找了很多RTP的代码,JRTPLIB就是其中一个,发现想做流媒体相关的应用,这些库所能提供的帮助是很小的。当时狠下心了,终于对MPEG有了一定的了解,RTP部分也是自己写的,虽然能工作但很不完善,写完后就有用JRTP的意图。这是写这个系列的原因之一,其二就是在我搜索有关JRTPLIB的相关内容时,竟然发现这么大一个因特网,竟然找不到用JRTPLIB实现的和流媒体相关的内容。整个国内在谈JRTPLIB的非常多,PUDN、CSDN等原码网站收集的原码也非常多,但令人气愤的是,这些不同名称的压缩包里头竟然全是JRTPLIB的原例程。JRTPLIB的官方例程?那不很好吗?NO!JRTPLIB的原列程(4个example和一个JRTPConsole)全和媒体流没关,example里就发发一些数字;JRTPConsole里就做一个服务器和一个客户端,也是发发数字。作者傻了吗,作者不知RTP是流媒体用的吗?NO,作者本来就没想过把JRTPLIB做为独立的软件包,JRTPLIB只是开发过程的其中一步,以这为出发点,测试程序发发数字,也没什么不可,能把JRTPLIB测试过就可以啦呀。如果大家去作者的网站看看就知道,作者写JRTPLIB是为了JVOIPLIB服务的,这才是作者想做的。而国内的人,却把这个测试程序当RTP的例程,我晕。更有“高手”做出了其于JRTPLIB的文件传送程序,狂晕,不知道RTP是传媒体流的,应该知道现的传文件都用FTP、HTTP呀。
      看到了如上这些现像,我有写点东西的想法,同时,我也可以过过兴趣。
      这是JRTPLIB@Conference 系列的第一编 开编。JRTPLIB@Conference系列的主要任务是通过JRTPLIB实现一个基于组播的会议系统,这里没有采用H323,也没有采用SIP,因为RTP本身就为媒体会议考虑得很周全。
      同时,在这里,我强调一下,JRTPLIB只是RTP协议的一个封装库,除此之外它不会实现任务的应用功能,想学完JRTPLIB就能写出媒体程序的就不用发白日梦了,想会用JRTPLIB用不用看RTP协议的也该醒了。要完最终的软件,我们必须清楚RTP协议和媒体相关的规范,周时会进行多媒体的编程(如MPEG的压缩、解压缩、采集、播放)。
      之前转载过一篇文章说RTP的,有图,也提到了JRTPLIB,把链接放在下面。
      http://www.cnitblog.com/tinnal/archive/2008/09/03/48674.html
      一些JRTPLIB的其本用法我就不说了,大家看看民JRTPLIB里的example就很清楚了。看不懂?那就BAIDU吧,国内全部网页都在给你解释那只个example.

      RTP的RFC:www.ietf.org/rfc/rfc3550.txt 



--------------------------------------------------------------------------------------------------------------------------------


JRTPLIB@Conference DIY视频会议系统 二、基本例程分析  

       转自   http://wmnmtm.blog.163.com/blog/static/382457142011540849714/


   这是JRTPLIB@Conference系列的第二部《基本例程分析》本系列的主要工作是实现一个基于JRTPLIB的,建立在RTP组播基础上的多媒体视频会议系统。这只是一个实验系统,用于学习JRTPLIB、RTP、和多媒体相关的编程,不是一个完善的软件工程。而且,我只会在业余的时间出于兴趣写一写。有志同道合的朋友可以通过tinnal@136.com这个邮箱或博客回复(推荐)和我交流。
      上一部:《JRTPLIB@Conference DIY视频会议系统 一、开编 
      这一部的原文为《linux下基于jrtplib库的实时传送实现》,这编文章虽然没有和媒体流相关,但作为JRTPLIB库的函数说明来看还是不错的。 主要的任务是通过例子初步看看如何通过JRTPLIB进行编程。这是进行JRTPLIB或RTP编程的入门编。
一、RTP 是进行实时流媒体传输的标准协议和关键技术
实时传输协议(Real-time Transport Protocol,PRT)是在 Internet 上处理多媒体数据流的一种网络协议,利用它能够在一对一(unicast,单播)或者一对多(multicast,多播)的网络环境中实现传流媒体数据的实时传输。RTP 通常使用 UDP来进行多媒体数据的传输,但如果需要的话可以使用 TCP 或者 ATM 等其它协议。
协议分析 :每一个RTP数据报都由头部(Header)和负载(Payload)两个部分组成,其中头部前 12 个字节的含义是固定的,而负载则可以是音频或者视频数据。
     RTP 是目前解决流媒体实时传输问题的最好办法,要在 Linux 平台上进行实时传送编程,可以考虑使用一些开放源代码的 RTP 库,如 LIBRTP、JRTPLIB 等。JRTPLIB 是一个面向对象的 RTP 库,它完全遵循 RFC 1889 设计,在很多场合下是一个非常不错的选择。JRTPLIB 是一个用 C++ 语言实现的 RTP 库,这个库使用socket 机制实现网络通讯 因此可以运行在 Windows、Linux、FreeBSD、Solaris、Unix和VxWorks 等多种操作系统上。
二、JRTPLIB 库的使用方法及程序实现
(1)JRTPLIB  函数 的使用
a、在使用 JRTPLIB 进行实时流媒体数据传输之前,首先应该生成 RTPSession 类的一个实例来表示此次 RTP 会话,然后调用 Create() 方法来对其进行初始化操作。RTPSession 类的 Create() 方法只有一个参数,用来指明此次 RTP 会话所采用的端口号。
RTPSession sess;  sess.Create(5000); 
b、设置恰当的时戳单元,是 RTP 会话初始化过程所要进行的另外一项重要工作,这是通过调用 RTPSession 类的 SetTimestampUnit() 方法来实现的,该方法同样也只有一个参数,表示的是以秒为单元的时戳单元。
sess.SetTimestampUnit(1.0/8000.0);
c、当 RTP 会话成功建立起来之后,接下去就可以开始进行流媒体数据的实时传输了。首先需要设置好数据发送的目标地址,RTP 协议允许同一会话存在多个目标地址,这可以通过调用 RTPSession 类的 AddDestination()、DeleteDestination() 和 ClearDestinations() 方法来完成。例如,下面的语句表示的是让 RTP 会话将数据发送到本地主机的 6000 端口: 
unsigned long addr = ntohl(inet_addr("127.0.0.1")); 
sess.AddDestination(addr, 6000);
d、目标地址全部指定之后,接着就可以调用 RTPSession 类的 SendPacket() 方法,向所有的目标地址发送流媒体数据。SendPacket() 是 RTPSession 类提供的一个重载函数
对于同一个 RTP 会话来讲,负载类型、标识和时戳增量通常来讲都是相同的,JRTPLIB 允许将它们设置为会话的默认参数,这是通过调用 RTPSession 类的 SetDefaultPayloadType()、SetDefaultMark() 和 SetDefaultTimeStampIncrement() 方法来完成的。为 RTP 会话设置这些默认参数的好处是可以简化数据的发送,例如,如果为 RTP 会话设置了默认参数: 
sess.SetDefaultPayloadType(0);
 sess.SetDefaultMark(false);  
sess.SetDefaultTimeStampIncrement(10);
之后在进行数据发送时只需指明要发送的数据及其长度就可以了: 
sess.SendPacket(buffer, 5); 
e、对于流媒体数据的接收端,首先需要调用 RTPSession 类的 PollData() 方法来接收发送过来的 RTP 或者 RTCP 数据报。由于同一个 RTP 会话中允许有多个参与者(源),你既可以通过调用 RTPSession 类的 GotoFirstSource() 和 GotoNextSource() 方法来遍历所有的源,也可以通过调用 RTPSession 类的 GotoFirstSourceWithData() 和 GotoNextSourceWithData() 方法来遍历那些携带有数据的源。在从 RTP 会话中检测出有效的数据源之后,接下去就可以调用 RTPSession 类的 GetNextPacket() 方法从中抽取 RTP 数据报,当接收到的 RTP 数据报处理完之后,一定要记得及时释放。
JRTPLIB 为 RTP 数据报定义了三种接收模式,其中每种接收模式都具体规定了哪些到达的 RTP 数据报将会被接受,而哪些到达的 RTP 数据报将会被拒绝。通过调用 RTPSession 类的 SetReceiveMode() 方法可以设置下列这些接收模式: 
? RECEIVEMODE_ALL  缺省的接收模式,所有到达的 RTP 数据报都将被接受; 
? RECEIVEMODE_IGNORESOME  除了某些特定的发送者之外,所有到达的 RTP 数据报都将被接受,而被拒绝的发送者列表可以通过调用 AddToIgnoreList()、DeleteFromIgnoreList() 和 ClearIgnoreList() 方法来进行设置; 
? RECEIVEMODE_ACCEPTSOME  除了某些特定的发送者之外,所有到达的 RTP 数据报都将被拒绝,而被接受的发送者列表可以通过调用 AddToAcceptList ()、DeleteFromAcceptList 和 ClearAcceptList () 方法来进行设置。 下面是采用第三种接收模式的程序示例。
if (sess.GotoFirstSourceWithData()) {   
 do {   
  sess.AddToAcceptList(remoteIP, allports,portbase);
         sess.SetReceiveMode(RECEIVEMODE_ACCEPTSOME);
   RTPPacket *pack;         
   pack = sess.GetNextPacket();            // 处理接收到的数据    
   delete pack;   } 
 while (sess.GotoNextSourceWithData()); 
 }
 (2)程序流程图
发送:获得接收端的 IP 地址和端口号        创建 RTP 会话        指定 RTP 数据接收端 设置 RTP 会话默认参数   发送流媒体数据
接收:获得用户指定的端口号  创建RTP会话  设置接收模式  接受RTP数据  检索RTP数据源  获取RTP数据报  删除RTP数据报
三、环境搭建及编译方法
引用
(1)Toolchain的安装
首先找到xscale-arm-toolchain.tgz文件,假设该文件包放在/tmp/下
#cd /
#tar -zxvf /tmp/xscale-arm-toolchain.tgz
再设置环境变量
#export PATH=/usr/local/arm-linux/bin:$PATH
最后检查一下交叉编译工具是否安装成功
#arm-linux-g++ --version
看是否显示arm-linux-g++的版本,如有则安装成功。
(2)JRTPLIB 库的交叉编译及安装
首先从 JRTPLIB 的网站(http://lumumba.luc.ac.be/jori/jrtplib/jrtplib.htmll) 下载最新的源码包,此处使用的是jrtplib-2.8.tar,假设下载后的源码包放在/tmp下,执 行下面的命令对其解压缩:
#cd /tmp
#tar -zxvf jrtplib-2.8.tar
然后要对jrtplib进行配置和编译
#cd jrtplib-2.8
#./configure CC=arm-linux-g++ cross-compile=yes
修改Makefile文件
将链接命令ld 和ar改为arm-linux-ld和 arm-linux-ar
#make
最后再执行如下命令就可以完成 JRTPLIB 的安装:
#make install
(3)程序编译
a、配置编译环境
可以用export来配置,也可以用编写Makefile的方法。这里采用Makefile。
编写Makefile&:
INCL = -I/usr/local/include
CFLAGS = -pipe -O2 -fno-strength-reduce
LFLAGS = /usr/local/lib/libjrtp.a -L/usr/X11R6/lib
LIBS = -LX11 -LXext /usr/local/lib/libjrtp.a
CC = arm-linux-g++
main:main.o
$(CC) $(LFLAGS) $(INCL) -o main main.o $(LIBS)
main.o:main.cpp
clean:
rm -f main
rm -f *.o
.SUFFIXES:.cpp
.cpp.o:
$(CC) -c $(CFLAGS) $(INCL) -o $@ $<         /*  $@表示目标的完整名字      */
         /* $<表示第一个依赖文件的名字 */
b、编译
假设发送和接收程序分别放在/tmp/send和/tmp/receive目录下
#cd /tmp/send
#make
#cd /tmp/receive
#make
四、易出错误及注意问题
引用
1、找不到一些标准的最 基本的一些头文件。
 主要是因为Toolchain路径没安装对,要 严格按照步骤安装。
2、找不到使用的jrtplib库中的一些头文件。
 在 jrtplib的安装目录下,include路径下不能再有别的目录。
3、recieve函数接收数据包不能正确提出所要数据。
 由于每一个RTP数据报都由头部(Header)和负载(Payload)两个部分组成,若使用getrawdata()是返回整个数据包的数据,包含传输媒体的类型、格式、序列号、时间戳以及是否有附加数据等信息。getpayload()函数是返回所发送的数据。两者一定要分清。
4、设置RECEIVEMODE_ACCEPTSOME  接收模式后,运行程序接收端不能接包。
 IP地址格式出了问题。iner_addr()与ntohl()函数要用对,否则参数传不进去,接受列表中无值,当然接收不了数据包。
5、编译通过,但测试时接收端不能接收到数据。
 可能是接收机防火墙未关闭。运行:
 #iptables -F
 也可能是IP地址没有设置好。运行:
 #ifocnfig eth0  *.*.*.*  netmask *.*.*.*
6、使用jrtolib库时,在程序中include 后最好加上库所在的路径。
五、程序
send:
view plaincopy to clipboardprint?
#include <stdio.h>    
#include <string.h>    
#include "rtpsession.h"    
   
// 错误处理函数    
void checkerror(int err)    
{    
  if (err < 0) {    
    char* errstr = RTPGetErrorString(err);    
    printf("Error:%s\\n", errstr);    
    exit(-1);    
  }    
}    
   
int main(int argc, char** argv)    
{    
  RTPSession sess;    
  unsigned long destip;    
  int destport;    
  int portbase = 6000;    
  int status, index;    
  char buffer[128];    
   
  if (argc != 3) {    
    printf("Usage: ./sender destip destport\\n");    
    return -1;    
  }    
   
  // 获得接收端的IP地址和端口号    
  destip = inet_addr(argv[1]);    
  if (destip == INADDR_NONE) {    
    printf("Bad IP address specified.\\n");    
    return -1;    
  }    
  destip = ntohl(destip);    
  destport = atoi(argv[2]);    
   
  // 创建RTP会话    
  status = sess.Create(portbase);    
  checkerror(status);    
   
  // 指定RTP数据接收端    
  status = sess.AddDestination(destip, destport);    
  checkerror(status);    
   
  // 设置RTP会话默认参数    
  sess.SetDefaultPayloadType(0);    
  sess.SetDefaultMark(false);    
  sess.SetDefaultTimeStampIncrement(10);    
   
  // 发送流媒体数据    
  index = 1;    
  do {    
    sprintf(buffer, "%d: RTP packet", index ++);    
    sess.SendPacket(buffer, strlen(buffer));    
    printf("Send packet !\\n");    
  } while(1);    
   
  return 0;    
}    
   
#include <stdio.h> #include <string.h> #include "rtpsession.h" // 错误处理函数 void checkerror(int err) {  if (err < 0) {    char* errstr = RTPGetErrorString(err);    printf("Error:%s\\n", errstr);    exit(-1);  } } int main(int argc, char** argv) {  RTPSession sess;  unsigned long destip;  int destport;  int portbase = 6000;  int status, index;  char buffer[128];  if (argc != 3) {    printf("Usage: ./sender destip destport\\n");    return -1;  }  // 获得接收端的IP地址和端口号  destip = inet_addr(argv[1]);  if (destip == INADDR_NONE) {    printf("Bad IP address specified.\\n");    return -1;  }  destip = ntohl(destip);  destport = atoi(argv[2]);  // 创建RTP会话  status = sess.Create(portbase);  checkerror(status);  // 指定RTP数据接收端  status = sess.AddDestination(destip, destport);  checkerror(status);  // 设置RTP会话默认参数  sess.SetDefaultPayloadType(0);  sess.SetDefaultMark(false);  sess.SetDefaultTimeStampIncrement(10);  // 发送流媒体数据  index = 1;  do {    sprintf(buffer, "%d: RTP packet", index ++);    sess.SendPacket(buffer, strlen(buffer));    printf("Send packet !\\n");  } while(1);  return 0; } 
receive:
view plaincopy to clipboardprint?
#include <stdio.h>    
#include "rtpsession.h"    
#include "rtppacket.h"    
   
// 错误处理函数    
void checkerror(int err)    
{    
  if (err < 0) {    
    char* errstr = RTPGetErrorString(err);    
    printf("Error:%s\\n", errstr);    
    exit(-1);    
  }    
}    
   
int main(int argc, char** argv)    
{    
  RTPSession sess;    
  int localport,portbase;    
  int status;    
  unsigned long remoteIP;    
  if (argc != 4) {    
    printf("Usage: ./sender localport\\n");    
    return -1;    
  }    
   
   // 获得用户指定的端口号    
       
  remoteIP = inet_addr(argv[1]);    
  localport = atoi(argv[2]);    
  portbase = atoi(argv[3]);    
  // 创建RTP会话    
  status = sess.Create(localport);    
  checkerror(status);    
      
  //RTPHeader *rtphdr;    
  unsigned long timestamp1;    
  unsigned char * RawData;    
  unsigned char temp[30];    
  int lengh ,i;    
  bool allports = 1;    
      
  sess.AddToAcceptList(remoteIP, allports,portbase);    
      
     do {    
 //设置接收模式    
        sess.SetReceiveMode(RECEIVEMODE_ACCEPTSOME);    
   sess.AddToAcceptList(remoteIP, allports,portbase);    
   
    // 接受RTP数据    
    status = sess.PollData();    
   
        
 // 检索RTP数据源    
    if (sess.GotoFirstSourceWithData()) {    
      do {    
            
        RTPPacket* packet;    
        // 获取RTP数据报    
        while ((packet = sess.GetNextPacket()) != NULL) {    
          printf("Got packet !\n");    
   
   timestamp1 = packet->GetTimeStamp();    
   lengh=packet->GetPayloadLength();    
   RawData=packet->GetPayload();    
       
   for(i=0;i<lengh;i++){    
      temp[i]=RawData[i];    
  printf("%c",temp[i]);    
   }    
   temp[i]='\0';    
   printf("  timestamp: %d lengh=%d data:%s\n",timestamp1,lengh,&temp);    
          // 删除RTP数据报    
       
          delete packet;    
        }    
      } while (sess.GotoNextSourceWithData());    
    }    
  } while(1);    
   
  return 0;    
}




-----------------------------------------------------------------------------------------------------------------------------



JRTPLIB@Conference DIY视频会议系统 三、JRTPLIB的几个重要类说明  

       转自  http://wmnmtm.blog.163.com/blog/static/382457142011540958700/

这是JRTPLIB@Conference系列的第三编《JRTPLIB的几个重要类说明》,本系列的主要工作是实现一个基于JRTPLIB的,建立在RTP组播基础上的多媒体视频会议系统。这只是一个实验系统,用于学习JRTPLIB、RTP、和多媒体相关的编程,不是一个完善的软件工程。而且,我只会在业余的时间出于兴趣写一写。有志同道合的朋友可以通过tinnal@136.com这个邮箱或博客回复(推荐)和我交流。
      上一部《JRTPLIB@Conference DIY视频会议系统 二、基本例程分析 》
      这一部的主要内容是要研究一个JRTPLIB常用的几个非常重要的类,在进行JRTPLIB或RTP编程时会经常和这个几类打交道,或都从这些类中继承。 
一、RTPSession
      对于大多数的RTP应用程序,RTPSession类可能是JRTPLIB唯一使用的类。它能完全处理RTCP部份的数据包,所以用户可以把精力集中在真正的数据收发。
      要知道RTPSession类在多线程下并不是安全的,因此,用户要通过某些锁同步机制来保证不会出现在不同线程当中调用同一个RTPSession实例。
      RTPSession类有如下的接口。
      ? RTPSession(RTPTransmitter::TransmissionProtocol proto = RTPTransmitter::IPv4UDPProto)
      使用proto类型传输层创建一个PRTSession实例。如果proto使用用户自定义(user-defined)传输层,则相应的NewUserDefinedTransmitter()函数必须实现。ps:这里默认就行了,默认就是IPV4网络。
      ? int Create(const RTPSessionParams &sessparams, const RTPTransmissionParams*transparams = 0)
      使用RTPSession参数sessparams和RTPTransmission参数transparams 真正创建一个RTP会话。如果transparams 为NULL,则使用默认的参数。ps:RTPSessionParams 我们可能要设得比较多,RTPTransmissionParams参数就只要设置其中的端口就行了,端口一定要设对,不然进行组播时,这个进程将不接收数据。设置方式可以看example.cpp。
      ? void Destroy()
      离开一个会话但不向其它组成员发送BYE包。ps:我不推荐用这个函数除非是错误处理,正常离开我们应该用ByeDestroy()。
      
      ? void BYEDestroy(const RTPTime &maxwaittime, const void *reason,size t reasonlength)
      发送一个BYE包并且离开会话。在发送BYE包前等待maxwaittime,如果超时,会不发送BYE包直接离开,BYE包会包含你的离开原因reason。相应的reasonlength表示reason长度。ps:因为BYE包是一个RTCP包,RTCP不是要发就发的,它的发送时间是为了平衡带宽通过计算得出来的,那就很有可能到了要发的时候以经超过了maxwaittime时间了,作者可能认一直保留个这会话这么久没意义。当然,我常常把maxwaittime设得很大。
      ? bool IsActive()
      看看这个RTPSession实例是否以经通过Create建立了真实的会话。
      ? uint32 t GetLocalSSRC()
      返回我们的SSRC。ps:至于什么是SSRC,去看看RFC3550吧。我说过JRTPLIB只是RTP协议的包装,并没有做任何应用的事情。
      ? int AddDestination(const RTPAddress &addr)
      添加一个发送目标。ps:当然,如果我们使用组播,这里只用调用一次,把我们的组播地址写进去。这样,这组的全部人都能收到你发的包。但是组播可因特网的上设置很烦。而且用组播测试也很烦(组播必须BIND一个端口,如果你想在同一台机器上运行两个软件实例来没试,你就会发现同一个端口BIND两次,当然,后面那次会失败,也就是说测试不了,要测?找两台机器,或用虚拟机JRTPLIB@Conference DIY视频会议系统 三、JRTPLIB的几个重要类说明 - 加菲 -  .),如果组播不满足,我们就要把组播变在单播,这时就要返复调用这个函数把其它组成员的IP都加进来了。具体可以看看example3.cpp。
      ? int DeleteDestination(const RTPAddress &addr)
      从发送地址列表中删除一下地址。
      ? void ClearDestinations()
      清除发送地址列表。
      ? bool SupportsMulticasting()
      返回JRTPLIB是否支持组播。ps:这里指JRTPLIB本身,不是你的真实网络。编译JRTPLIB库时可能指定。
.
      ? int JoinMulticastGroup(const RTPAddress &addr)
      加入一个组播组addr。
      ? int LeaveMulticastGroup(const RTPAddress &addr)
       离开一个组播组addr。
      ? void LeaveAllMulticastGroups()
      离开所有组播组。ps:我们可以同时加入多个组播组。.
      ? int SendPacket(const void *data, size t len)
      ? int SendPacket(const void *data, size t len, uint8 t pt, bool mark,uint32 t timestampinc)
      ? int SendPacketEx(const void *data, size t len, uint16 t hdrextID,const void *hdrextdata, size t numhdrextwords)
      ? int SendPacketEx(const void *data, size t len, uint8 t pt, boolmark, uint32 t timestampinc, uint16 t hdrextID, const void *hdrextdata,size t numhdrextwords)
      上面的4个函数都是发送数据包的,我想如果你没有看RTP协议,我说了你也晕。如果你RTP协议看了,再看看RTPSession.h的注识,你就懂了。
      ? int SetDefaultPayloadType(uint8 t pt)
      设定默认的RTP PayloadType为PT。ps:和上面的第一个和第三个发送函数配套。至于应该设个什么数,如果你看BAIDU上乱七八糟的文章,当然的乱设就可能了。其实应该按RFC3551,根据你要传输的媒体类型来设。
      ? int SetDefaultMark(bool m)
      这设RTP数据包的Mark标识。ps:设为什么值好?这个,呵呵,连RFC3550也不能确定了。要看具体的RTP Payload规范,MPEG的,H263的都不一样。
      MPEG2    www.ietf.org/rfc/rfc2250.txt 
      MPEG4    www.rfc-editor.org/rfc/rfc3016.txt 
      H263        www.ietf.org/rfc/rfc2190.txt 
      ? int SetDefaultTimestampIncrement(uint32 t timestampinc)
      设置默认的时间戳的增量。ps:也是和上的第一和第三个函数配套的。每发一个RTP数据包timestamp就会自动增加
      ? int IncrementTimestamp(uint32 t inc)
      这个函数用来手工增加Timestamp。有时我这很好用,例如,一个RTP数据包因为只含有静音数据,我们没有发送,这是我们就应手工增加Timestamp以便发下一个RTP数据包时它的Timestamp是正确的。
      ? int IncrementTimestampDefault()
      这个函数用于增加由SetDefaultTimestampIncrement设定的值。有时候这很有用,例如,一个RTP数据包因为只含有静音数据,我们没有发送。这时,这个函数就会被调用用来设置Timestamp以便下一个RTP包的Timestamp是正确的。
      ? int SetPreTransmissionDelay(const RTPTime &delay)
      This function allows you to inform the library about the delay between
sampling the first sample of a packet and sending the packet. This delay is
taken into account when calculating the relation between RTP timestamp
and wallclock time, used for inter-media synchronization.
      ? RTPTransmissionInfo *GetTransmissionInfo()
      This function returns an instance of a subclass of RTPTransmissionInfo
which will give some additional information about the transmitter (a list
of local IP addresses for example). The user has to delete the returned
instance when it is no longer needed.
      
      ? int Poll()
      If you’re not using the poll thread, this function must be called regularly
to process incoming data and to send RTCP data when necessary.
61
      ? int WaitForIncomingData(const RTPTime &delay,bool *dataavailable= 0)
      Waits at most a time delay until incoming data has been detected. Only
works when you’re not using the poll thread. If dataavailable is not NULL,
it should be set to true if data was actually read and to false otherwise.
      ? int AbortWait()
      If the previous function has been called, this one aborts the waiting. Only
works when you’re not using the poll thread.
      ? RTPTime GetRTCPDelay()
      Returns the time interval after which an RTCP compound packet may have
to be sent. Only works when you’re not using the poll thread.
      ? int BeginDataAccess()
      下面的函数(直到EndDataAccess)要在BeginDataAccess 和EndDataAccess之间被调用,BeginDataAccess确保轮询(poll)线程不会在这期间访问source table 。EndDataAccess 调用完成后,轮询(poll)线程会得到锁而继续访问。ps:首先,你里的source table中的每一个source表示参与会议中的每一个参与者的每一个独立的媒体流。我们会在下面用到他们,但同时,poll线程也会轮询它们以正确处理和RTCP有关的内容。
  
      ? bool GotoFirstSource()
      开始递归参与者的第一个流,如果找到了,就返回tree,否则返回false。ps:我们通过这个函数和下面的GotoNextSource遍历source table中的每一个source。
      
      ? bool GotoNextSource()
      设置当前的源(source)为source table中的下一个源。如果已经到尾部了就返回false.
     
      ? bool GotoPreviousSource()
      设置当前的源(source)为source table中上一个源。如果已经到头部了就返回false.
      ? bool GotoFirstSourceWithData()
      开始递归参与者中第一个有RTP数据的流,如果找到了,就返回tree,否则返回false。PS:在接收数据是我们常用的是这套函数,因为如果没有数据要来都没用。
      ? bool GotoNextSourceWithData()
      设置当前的源(source)为source table中有RTP数据的下一个源。如果已经到尾部了就返回false.
      ? bool GotoPreviousSourceWithData()
      设置当前的源(source)为source table中有RTP数据的上一个源。如果已经到头部了就返回false.
      ? RTPSourceData *GetCurrentSourceInfo()
      返回当前参与者的当前源(source)的RTPSourceData 实列。ps:返回的这个RTPSourceData 就是本进程从期它参与者的RTCP数据包中收集得到的信息,对我们来说其实很有用,只是作者的例程没有用上,国内的网络也没有提到。在RFC3550中有关RTCP的东西都在这了,看过RFC3550的人都知到,里头谈得最多的就是RTCP。这个类我们以后会专门说。
      
      
      ? RTPSourceData *GetSourceInfo(uint32 t ssrc)
      返回由ssrc指定的RTPSourceData ,或都NULL(当这个条目不存在)。ps:这个函数也很有用。因为GetCurrentSourceInfo只有在GotoFirstSource等上下文当中才能用。如果我们是在RTPSource子类的成员函数中,我们没有这个上下文,就只能用这个函数。
 
      ? RTPPacket *GetNextPacket()
      得到当前参与者当前媒体流的下一个RTP数据包。
      ? int EndDataAccess()
      请看BeginDataAccess
      ? int SetReceiveMode(RTPTransmitter::ReceiveMode m)
      Sets the receive mode to m, which can be one of the following:
      – RTPTransmitter::AcceptAll
            All incoming data is accepted, no matter where it originated from.
      – RTPTransmitter::AcceptSome
            Only data coming from specific sources will be accepted.
      – RTPTransmitter::IgnoreSome
            All incoming data is accepted, except for data coming from a specificset of sources.
        Note that when the receive mode is changed, the list of addressed to be ignored or accepted will be cleared.
      ? int AddToIgnoreList(const RTPAddress &addr)
      Adds addr to the list of addresses to ignore.
      ? int DeleteFromIgnoreList(const RTPAddress &addr)
      Deletes addr from the list of addresses to ignore.
      ? void ClearIgnoreList()
      Clears the list of addresses to ignore.
      ? int AddToAcceptList(const RTPAddress &addr)
      Adds addr to the list of addresses to accept.
      ? int DeleteFromAcceptList(const RTPAddress &addr)
      Deletes addr from the list of addresses to accept.
      ? void ClearAcceptList()
      Clears the list of addresses to accept.
      ? int SetMaximumPacketSize(size t s)
      Sets the maximum allowed packet size to s.
      ? int SetSessionBandwidth(double bw)
      Sets the session bandwidth to bw, which is specified in bytes per second.
      ? int SetTimestampUnit(double u)
      Sets our own timestamp unit to u. The timestamp unit is defined as a time
interval divided by the number of samples in that interval: for 8000Hz
audio this would be 1.0/8000.0.
      ? void SetNameInterval(int count)
      在处理source table中的sourcese后,RTCP packet builder(我们不用理这个内部的东西)会检查是否有其它(non-CNAME)SDES项目要发送。如果count为零或负数,则不发送,如果count为正数,则在sources table处理count次后会把SDES name item加到当前RTCP包中。ps:其实每次处理sources table都会伴随都SDES RTCP数据包的发送,在这个数据包当中CNAME是必须的,但其它的项目不是必须的,这就函数确定了NAME项目发送的频度,如果为1,则表不每个SDES RTCP数据包都带着它,如果为2则每两个SDES数据包就发送一次NAME项目,下面的SetEMailInterval、SetLocationInterval、SetPhoneInterval、SetToolInterval、SetNoteInterval都是同一原理。关于这个ITEM的描述,请看RFC3550.老版本的JRTPLIB没有使用这套函数,而是用EnableSendName()等函数。
      ? void SetEMailInterval(int count)
      After all possible sources in the source table have been processed, the RTCP
packet builder will check if other (non-CNAME) SDES items need to be
sent. If count is zero or negative, nothing will happen. If count is positive,
an SDES e-mail item will be added after the sources in the source table
have been processed count times.
      ? void SetLocationInterval(int count)
      After all possible sources in the source table have been processed, the RTCP
packet builder will check if other (non-CNAME) SDES items need to be
sent. If count is zero or negative, nothing will happen. If count is positive,
an SDES location item will be added after the sources in the source table
have been processed count times.
      ? void SetPhoneInterval(int count)
      After all possible sources in the source table have been processed, the RTCP
packet builder will check if other (non-CNAME) SDES items need to be
sent. If count is zero or negative, nothing will happen. If count is positive,
an SDES phone item will be added after the sources in the source table
have been processed count times.
      ? void SetToolInterval(int count)
      After all possible sources in the source table have been processed, the RTCP
packet builder will check if other (non-CNAME) SDES items need to be
sent. If count is zero or negative, nothing will happen. If count is positive,
an SDES tool item will be added after the sources in the source table have
been processed count times.
      ? void SetNoteInterval(int count)
      After all possible sources in the source table have been processed, the RTCP
packet builder will check if other (non-CNAME) SDES items need to be
sent. If count is zero or negative, nothing will happen. If count is positive,
an SDES note item will be added after the sources in the source table have
been processed count times.
      ? int SetLocalName(const void *s, size t len)
      设置NAME SDES项目,以遍会议的其它人员看到你的名称。下同。
     
      ? int SetLocalEMail(const void *s, size t len)
      Sets the SDES e-mail item for the local participant to the value s with
length len.
      ? int SetLocalLocation(const void *s, size t len)
Sets the SDES location item for the local participant to the value s with
length len.
      ? int SetLocalPhone(const void *s, size t len)
      Sets the SDES phone item for the local participant to the value s with
length len.
      ? int SetLocalTool(const void *s, size t len)
      Sets the SDES tool item for the local participant to the value s with length
len.
      
      ? int SetLocalNote(const void *s, size t len)
Sets the SDES note item for the local participant to the value s with length
len.
In case you specified in the constructor that you want to use your own transmission
component, you should override the following function:
      ? RTPTransmitter *NewUserDefinedTransmitter()
      The RTPTransmitter instance returned by this function will then be used to send
and receive RTP and RTCP packets. Note that when the session is destroyed,
this RTPTransmitter instance will be destroyed with a delete call.
By inheriting your own class from RTPSession and overriding one or more of the
functions below, certain events can be detected:
      ? void OnRTPPacket(RTPPacket *pack, const RTPTime &receivetime, const  RTPAddress *senderaddress)
      如果有RTPPacket数据包来到,会调用这个函数处理。ps:这个函数在我们继承RTPSession类时很可能重载,这是获取RTP数据包除了上面所说的方法以外的另外一种方法,这个方法比较适合异步的情况。默认这个是一个空虚函数。除了这个函数以外,下面的几个函数了会经常重载。
      ? void OnRTCPCompoundPacket(RTCPCompoundPacket *pack, const RTPTime &receivetime, const RTPAddress *senderaddress)
      Is called when an incoming RTCP packet is about to be processed.
      ? void OnSSRCCollision(RTPSourceData *srcdat, const RTPAddress *senderaddress, bool isrtp)
      Is called when an SSRC collision was detected. The instance srcdat is the
one present in the table, the address senderaddress is the one that collided
with one of the addresses and isrtp indicates against which address
of srcdat the check failed.
      
      ? void OnCNAMECollision(RTPSourceData *srcdat, const RTPAddress *senderaddress, const uint8 t *cname, size t cnamelength)
      Is called when another CNAME was received than the one already present for source srcdat.
      ? void OnNewSource(RTPSourceData *srcdat)
      当有一个新的条目加到source table时,调用这个函数。ps:这也是一个比较重要的函数,因为这意味着很有可能有一个新的与会者加入。但令我很不高兴的是,这时候的RTPSourceData 里头的CNAME和NAME等字段都还是无效的,这不是RTCP的责任,因为在这个SDES RTCP数据包中所有的信息都以经有了(通过抓包证实了这一点)。我们的函数被调用后,需要延时一会才能得到有关这个Source的CNAME和NAME等相关的信息。当然,如果你不想软件死掉,不能在这个函数体内以阻塞的方式延时。
      ? void OnRemoveSource(RTPSourceData *srcdat)
      当有一个条目从source table中移除时调用这个函数。ps:这通常意味着有一个与会者离开了,和OnNewSource不一样,这时的CNAME和NAME等都是有效的。用这个函数要注意,我们的“意味着两个字”因为“加入”的可能不是一个新的与会者,而是一个现有与会者的一个新的媒体流。“离开”的也可能不是一个与会者,而只是其中一个与会者的其中一个媒体流,这两个函数只能给我们更新与会者提供一个触发条件而已。当OnNewSource调用时,我们要看看这个CNAME是不是以经在我们与会者名单中,如果不是,那就是一个新与会者。同时,如果OnRemoveSource被调用,则我们要看看这个CNAME的与会者还有没有其它的Source,如果没有了,这个与会者才是真正离开。这么很麻烦??那就对了,那就是现在的H323和SIP要做的事情--会话管理。
     
      ? void OnTimeout(RTPSourceData *srcdat)
      Is called when participant srcdat is timed out.
      ? void OnBYETimeout(RTPSourceData *srcdat)
      Is called when participant srcdat is timed after having sent a BYE packet.
      ? void OnBYEPacket(RTPSourceData *srcdat)
      Is called when a BYE packet has been processed for source srcdat.
      ? void OnAPPPacket(RTCPAPPPacket *apppacket, const RTPTime &receivetime,
const RTPAddress *senderaddress)
      In called when an RTCP APP packet apppacket has been received at time
receivetime from address senderaddress.
      ? void OnUnknownPacketType(RTCPPacket *rtcppack, const RTPTime &receivetime,
const RTPAddress *senderaddress)
      Is called when an unknown RTCP packet type was detected.
      ? void OnUnknownPacketFormat(RTCPPacket *rtcppack, const RTPTime &receivetime,
const RTPAddress *senderaddress)
      Is called when an unknown packet format for a known packet type was
detected.
      ? void OnNoteTimeout(RTPSourceData *srcdat)
      Is called when the SDES NOTE item for source srcdat has been timed out.
      ? void OnSendRTCPCompoundPacket(RTCPCompoundPacket *pack)
      Is called when an RTCP compound packet has just been sent. Useful to
inspect outgoing RTCP data.
      ? void OnPollThreadError(int errcode)
      Is called when error errcode was detected in the poll thread.
      ? void OnPollThreadStep()
      Is called each time the poll thread loops. This happens when incoming data
was detected or when its time to send an RTCP compound packet.
      原来想全部翻译的,翻译真的累,后我我只翻译了一部份,其它有时间我会慢慢翻译的。PS后面的话是原文没有的,是我加上去的。其它是原文有的。
      原文:jrtplib.pdf(英文原搞)


---------------------------------------------------------------------------------------------------------------------------------


JRTPLIB@Conference DIY视频会议系统 三、JRTPLIB的几个重要类说明(续一)

转自  http://wmnmtm.blog.163.com/blog/static/3824571420115401049859/


 这是JRTPLIB@Conference系列的第三编《JRTPLIB的几个重要类说明》,本系列的主要工作是实现一个基于JRTPLIB的,建立在RTP组播基础上的多媒体视频会议系统。这只是一个实验系统,用于学习JRTPLIB、RTP、和多媒体相关的编程,不是一个完善的软件工程。而且,我只会在业余的时间出于兴趣写一写。有志同道合的朋友可以通过tinnal@136.com这个邮箱或博客回复(推荐)和我交流。
      上一部《JRTPLIB@Conference DIY视频会议系统 二、基本例程分析 》
      这一部的主要内容是要研究一个JRTPLIB常用的几个非常重要的类,在进行JRTPLIB或RTP编程时会经常和这个几类打交道,或都从这些类中继承。

       这是续上一编《JRTPLIB@Conference DIY视频会议系统 三、JRTPLIB的几个重要类说明 》的,上一编中,我们研究了JRTPLIB中的一个重要的类RTPSesseion,我们现在来讲一下另外一个类RTPPacket。
二、 RTPPacket
       RTPPacket 类用于处理属于RTP类型的RTPRawPacket,这个类可以用根据用户设定的参数创建一个新的RTP数据包。这个类的接口如下:
      ? RTPPacket(RTPRawPacket &rawpack)
      这个构造函数根据rawpack数据包构造RTPPacket对像
   ? RTPPacket(uint8 t payloadtype, const void *payloaddata, size t payloadlen,
      uint16 t seqnr, uint32_t timestamp, uint32_t ssrc, bool gotmarker,
      uint8 t numcsrcs, const uint32_t *csrcs, bool gotextension, uint16_t
      extensionid, uint16 t extensionlen numwords, const void *extensiondata,
      size t maxpacksize = 0)
      为RTP新建一个缓冲区,并且根据指定的参数填充数据包。如果maxpacksize 不等于0,则如果数据包大于此值会返回错误。参数请根据RFC3550规定填写,header extension 是以32位计的。
      ? RTPPacket(uint8 t payloadtype, const void *payloaddata, size t payloadlen,
      uint16 t seqnr, uint32 t timestamp, uint32 t ssrc, bool gotmarker,
      uint8 t numcsrcs, const uint32 t *csrcs, bool gotextension, uint16 t
      extensionid, uint16 t extensionlen numwords, const void *extensiondata,
      void *buffer, size t buffersize)
      和上一个函数很像,只是它把数据存在buffersize大小的外部Buffer当中。
      ? int GetCreationError() const
      如果任何一个构造函数有错,这个函数会返回错误码。
      ? bool HasExtension() const
       如果有RTP扩展头部,这个函数会返回真。
      ? bool HasMarker() const
      如果RTP头部设置了Make标志,这个函数会返回真。
      ? int GetCSRCCount() const
       返回这个RTP包的CSRC值的数量。
      ? uint32 t GetCSRC(int num) const
      返回这个RTP流的特定作用流标识。num从0 到GetCSRCCount()-1有效
     
      ? uint8 t GetPayloadType() const
      返回这个RTP流的类型
      ? uint32 t GetExtendedSequenceNumber() const
      返加这个包的扩展序列号(extended sequence number ),如果这个包刚收到,只有低16位才有效,高16位销后才会填充。
      ? uint16 t GetSequenceNumber() const
      返回RTP数据包中的序列号字段
      ? void SetExtendedSequenceNumber(uint32 t seq)
      设置这个包的扩展序列号
      ? uint32 t GetTimestamp() const
      返回这个RTP包的时间戳
      ? uint32 t GetSSRC() const
      返回这个RTP包的SSRC值。ps:这个非常重要,通过这个SSRC值,我们可以用RTPSourceData *GetSourceInfo(uint32 t ssrc)获取这个RTP流相关的信息!
      ? uint8 t *GetPacketData() const
      返回这个RTP包的地址。
      ? uint8 t *GetPayloadData() const
      返回这个RTP包有效负载的地址。ps:这是我们最常用的函数
      ? size t GetPacketLength() const
      返回RTP数据包的长度
      ? size t GetPayloadLength() const
      返回RTP有效负载的长度。
      ? uint16 t GetExtensionID() const
      如果有扩展头部,返回扩展头部的ID。
      ? uint8 t *GetExtensionData() const
      返回扩展头部的内容
      ? size t GetExtensionLength() const
      返回扩展头部的长度
      ? RTPTime GetReceiveTime() const
      当一个数据包接收进来,构造成为RTPPacket时,数据包的接收时间就会储存在RTPPacket内部,这个函数读取这个时间。



---------------------------------------------------------------------------------------------------------------------------------


JRTPLIB@Conference DIY视频会议系统 三、JRTPLIB的几个重要类说明(续二)  


转自 http://wmnmtm.blog.163.com/blog/static/3824571420115401143819/


  这是JRTPLIB@Conference系列的第三编《JRTPLIB的几个重要类说明》,本系列的主要工作是实现一个基于JRTPLIB的,建立在RTP组播基础上的多媒体视频会议系统。这只是一个实验系统,用于学习JRTPLIB、RTP、和多媒体相关的编程,不是一个完善的软件工程。而且,我只会在业余的时间出于兴趣写一写。有志同道合的朋友可以通过tinnal@136.com这个邮箱或博客回复(推荐)和我交流。
      上一部《JRTPLIB@Conference DIY视频会议系统 二、基本例程分析 》
      这一部的主要内容是要研究一个JRTPLIB常用的几个非常重要的类,在进行JRTPLIB或RTP编程时会经常和这个几类打交道,或都从这些类中继承。

       这是续上一编《JRTPLIB@Conference DIY视频会议系统 三、JRTPLIB的几个重要类说明(续一)》的,上一编中,我们研究了JRTPLIB中的一个重要的类RTPPacket,我们现在来讲一下另外一个类RTPSourceData。
三、 RTPSourceData
头文件:rtpsourcedata.h
RTPSourceData 类收集了有关这个会话的某一个源的所有信息(ps:这些信息其实也就是从其它组成员的RTCP数据包中获得)。接口如下:
   
      ? uint32 t GetSSRC() const
      返回这个源的SSRC标识符
      ? bool HasData() const
      看看这个源是否有RTP数据可能提取
      ? RTPPacket *GetNextPacket()
      从这个源的RTP包队列中提取第一个数据包
      ? void FlushPackets()
      清空这个源的RTP包队列
      ? bool IsOwnSSRC() const
      如果这个源是由RTPSources成员函数CreateOwnSSRC加入的,就返回真。PS:如果为真,那就是我们自己了。:)
      ? bool IsCSRC() const
      如果这个源是由的RTP数据包而加入的,就返回真,否则返回假。
      ? bool IsSender() const
      如果我们是发送者,则返回真。PS:至于怎么才是发送者,请看RFC3550
      ? bool IsValidated() const
      看看这个源是否有效:收到一定数的连续的RTP数据包或一个CNAME项目。则返回真,否则返回假。
      ? bool IsActive() const
      如果这个源有效,而且没有收到BYE数据包,则这源是活动的,返回真,否则返回假。
      ? void SetProcessedInRTCP(bool v)
       这个函数是由RTCPPacketBuilder调用,用于标识这些个源的在report block中的信息是否已经处理。
      ? bool IsProcessedInRTCP() const
      这个函数是由RTCPPacketBuilder调用,用于判断report block中的信息是否已经处理。
      ? bool IsRTPAddressSet() const
      如果这个源的RTP数据包源IP地址已经设置过,则返回真,否则返回假。
      ? bool IsRTCPAddressSet() const
      如果这个源的RTP数据包源IP地址已经设置过,则返回真,否则返回假。
      ? const RTPAddress *GetRTPDataAddress() const
      返回这个源的RTP数据包的源IP地址,如果这个地址已经设置了(通过IsRTPAddressSet函数判断就可以)但却返回NULL,则标志这个包是我们自己发的。
      ? const RTPAddress *GetRTCPDataAddress() const
      返回这个源的RTCP数据包的源IP地址,如果这个地址已经设置了(通过IsRTCPAddressSet函数判断就可以)但却返回NULL,则标志这个包是我们自己发的。
      ? bool ReceivedBYE() const
      如果为真表明收到一个BYE数据包
      ? uint8 t *GetBYEReason(size t *len) const
      得到BYE的源因
      
      ? RTPTime GetBYETime() const
       返回BYE的时间
      ? void SetTimestampUnit(double tsu)
      Sets the value for the timestamp unit to be used in jitter calculations for data received from this participant. If not set, the library uses an approximation for the timestamp unit which is calculated from two consecutive RTCP sender reports. The timestamp unit is defined as a time interval
divided by the number of samples in that interval: for 8000Hz audio this would be 1.0/8000.0.
      ? double GetTimestampUnit() const
      Returns the timestamp unit used for this participant.
      
      ? bool SR HasInfo() const
      Returns true if an RTCP sender report has been received from this participant.
      ? RTPNTPTime SR GetNTPTimestamp() const
      Returns the NTP timestamp contained in the last sender report.
      ? uint32 t SR GetRTPTimestamp() const
      Returns the RTP timestamp contained in the last sender report.
      ? uint32 t SR GetPacketCount() const
      Returns the packet count contained in the last sender report.
      ? uint32 t SR GetByteCount() const
      Returns the octet count contained in the last sender report.
      ? RTPTime SR GetReceiveTime() const
      Returns the time at which the last sender report was received.
      ? bool SR Prev HasInfo() const
      Returns true if more than one RTCP sender report has been received.
      ? RTPNTPTime SR Prev GetNTPTimestamp() const
      Returns the NTP timestamp contained in the second to last sender report.
      ? uint32 t SR Prev GetRTPTimestamp() const
      Returns the RTP timestamp contained in the second to last sender report.
      
      ? uint32 t SR Prev GetPacketCount() const
      Returns the packet count contained in the second to last sender report.
      ? uint32 t SR Prev GetByteCount() const
      Returns the octet count contained in the second to last sender report.
      ? RTPTime SR Prev GetReceiveTime() const
      Returns the time at which the second to last sender report was received.
      ? bool RR HasInfo() const
      Returns true if this participant sent a receiver report with information about the reception of our data.
      ? double RR GetFractionLost() const
      Returns the fraction lost value from the last report.
      ? int32 t RR GetPacketsLost() const
      Returns the number of lost packets contained in the last report.
      ? uint32 t RR GetExtendedHighestSequenceNumber() const
      Returns the extended highest sequence number contained in the last report.
      ? uint32 t RR GetJitter() const
      Returns the jitter value from the last report.
      ? uint32 t RR GetLastSRTimestamp() const
      Returns the LSR value from the last report.
      ? uint32 t RR GetDelaySinceLastSR() const
      Returns the DLSR value from the last report.
      ? RTPTime RR GetReceiveTime() const
      Returns the time at which the last report was received.
      ? bool RR Prev HasInfo() const
      Returns true if this participant sent more than one receiver report with information about the reception of our data.
      ? double RR Prev GetFractionLost() const
      Returns the fraction lost value from the second to last report.
      ? int32 t RR Prev GetPacketsLost() const
      Returns the number of lost packets contained in the second to last report.
      ? uint32 t RR Prev GetExtendedHighestSequenceNumber() const
      Returns the extended highest sequence number contained in the second to last report.
      ? uint32 t RR Prev GetJitter() const
      Returns the jitter value from the second to last report.
      ? uint32 t RR Prev GetLastSRTimestamp() const
      Returns the LSR value from the second to last report.
      ? uint32 t RR Prev GetDelaySinceLastSR() const
      Returns the DLSR value from the second to last report.
      ? RTPTime RR Prev GetReceiveTime() const
      Returns the time at which the second to last report was received.
      ? bool INF HasSentData() const
      Returns true if validated RTP packets have been received from this participant.
      ? int32 t INF GetNumPacketsReceived() const
      Returns the total number of received packets from this participant.
      ? uint32 t INF GetBaseSequenceNumber() const
      Returns the base sequence number of this participant.
      ? uint32 t INF GetExtendedHighestSequenceNumber() const
      Returns the extended highest sequence number received from this participant.
      ? uint32 t INF GetJitter() const
      Returns the current jitter value for this participant.
      ? RTPTime INF GetLastMessageTime() const
      Returns the time at which something was last heard from this member.
      ? RTPTime INF GetLastRTPPacketTime() const
      Returns the time at which the last RTP packet was received.
      ? double INF GetEstimatedTimestampUnit() const
      Returns the estimated timestamp unit. The estimate is made from two consecutive sender reports.
      ? uint32 t INF GetNumPacketsReceivedInInterval() const
      Returns the number of packets received since a new interval was started with INF StartNewInterval.
      ? uint32 t INF GetSavedExtendedSequenceNumber() const
      Returns the extended sequence number which was stored by the INF StartNewInterval call.
      ? void INF StartNewInterval()
      Starts a new interval to count received packets in. This also stores the current extended highest sequence number to be able to calculate the packet loss during the interval.
      ? RTPTime INF GetRoundtripTime() const
      Estimates the round trip time by using the LSR and DLSR info from the last receiver report.
      ? RTPTime INF GetLastSDESNoteTime() const
      Returns the time at which the last SDES NOTE item was received.
      ? uint8 t *SDES GetCNAME(size t *len) const
      Returns a pointer to the SDES CNAME item of this participant and stores its length in len.
      ? uint8 t *SDES GetName(size t *len) const
      Returns a pointer to the SDES name item of this participant and stores its length in len.
      ? uint8 t *SDES GetEMail(size t *len) const
      Returns a pointer to the SDES e-mail item of this participant and stores its length in len.
      ? uint8 t *SDES GetPhone(size t *len) const
      Returns a pointer to the SDES phone item of this participant and stores its length in len.
      
      ? uint8 t *SDES GetLocation(size t *len) const
      Returns a pointer to the SDES location item of this participant and stores its length in len.
      ? uint8 t *SDES GetTool(size t *len) const
      Returns a pointer to the SDES tool item of this participant and stores its length in len.
      ? uint8 t *SDES GetNote(size t *len) const
      Returns a pointer to the SDES note item of this participant and stores its length in len.
      If SDES private item support was enabled at compile-time, the following member functions are also available:
      ? void SDES GotoFirstPrivateValue()
      Starts the iteration over the stored SDES private item prefixes and their associated values.
      ? bool SDES GetNextPrivateValue(uint8 t **prefix, size t *prefixlen,uint8 t **value, size t *valuelen)
      If available, returns true and stores the next SDES private item prefix in prefix and its length in prefixlen. The associated value and its length are then stored in value and valuelen. Otherwise, it returns false.
      ? bool SDES GetPrivateValue(uint8 t *prefix, size t prefixlen, uint8 t **value, size t *valuelen) const
      Looks for the entry which corresponds to the SDES private item prefix prefix with length prefixlen. If found, the function returns true and stores the associated value and its length in value and valuelen respectively.




------------------------------------------------------------------------------------------------------------------------------------


JRTPLIB@Conference DIY视频会议系统 四、JRTPLIB组成的文字会议测试  

转自  http://wmnmtm.blog.163.com/blog/static/3824571420115401227828/


      这是JRTPLIB@Conference系列的第四部《JRTPLIB组成的文字会议测试 》,本系列的主要工作是实现一个基于JRTPLIB的,建立在RTP组播基础上的多媒体视频会议系统。这只是一个实验系统,用于学习JRTPLIB、RTP、和多媒体相关的编程,不是一个完善的软件工程。而且,我只会在业余的时间出于兴趣写一写。有志同道合的朋友可以通过tinnal@136.com这个邮箱或博客回复(推荐)和我交流。
      上一部《JRTPLIB@Conference DIY视频会议系统 三、JRTPLIB的几个重要类说明 》
      这一部的主要内完是完成基于组播的视频会议系统中的其中一部份--会话管理。我们将通过一个文字会议测试程序来测试JRTPLIB的会话管理。当然,这里用的是RTP本身的基于组播会话管理,没有你们梦想的SIP,更没有庞大的H323。SIP和H323等我研究到了再写。JRTPLIB@Conference DIY视频会议系统 四、JRTPLIB组成的文字会议测试 - 加菲 -  .
      先占个位,代码是写完了,懒得写文字。JRTPLIB@Conference DIY视频会议系统 四、JRTPLIB组成的文字会议测试 - 加菲 -  .


-----------------------------------------------------------------------------------------------------------------------------------


JRTPLIB@Conference DIY视频会议系统 五、PCM 和G.711编码相关  

转自  http://wmnmtm.blog.163.com/blog/static/3824571420115401437663/


   这是JRTPLIB@Conference系列的第五部《PCM 和G.711编码相关》,本系列的主要工作是实现一个基于JRTPLIB的,建立在RTP组播基础上的多媒体视频会议系统。这只是一个实验系统,用于学习JRTPLIB、RTP、和多媒体相关的编程,不是一个完善的软件工程。而且,我只会在业余的时间出于兴趣写一写。有志同道合的朋友可以通过tinnal@136.com这个邮箱或博客回复(推荐)和我交流。
      上一部《JRTPLIB@Conference DIY视频会议系统 四、JRTPLIB组成的文字会议测试 》
      这一部的主要内容是研究音频编码的,现在VOIP在语音编码方面已经取得了很多的成果,5到6Kbps的带宽就能传送一路高质量语音,也就是说,就用我97年上网时用的那个33.6K的猫上网,都能传6-7路语音。当然,我们不会在这里谈这个高级编码器,我们可会把它们放在这一系列的后面作扩展的时候研究,看到时候的情况吧。我们现在要谈的是两个非常重要的编码,一个是PCM,一个是G.711。PCM就是我们Windows下的一堆WAV文件的基本音频编码格式,够常用了吧。G.711是VOIP要求每一个接入设备必须支持的编码器。
      我找了下中文的说明,我现很少,找了一些英文的资料,对这些编码不熟得就看看吧。
一、PCM
Pulse-code modulation
Pulse-code modulation (PCM) is a digital representation of an analog signal where the magnitude of the signal issampled regularly at uniform intervals, then quantized to a series of symbols in a numeric (usually binary) code. PCM has been used in digital telephone systems and 1980s-era electronic musical keyboards. It is also the standard form fordigital audio in computers and the compact disc "red book" format. It is also standard in digital video, for example, usingITU-R BT.601. However, uncompressed PCM is not typically used for video in standard definition consumer applications such as DVD or DVR because the bit rate required is far too high. The only consumer video format that used Uncompressed PCM was the Laserdisc format.
Modulation

In the diagram, a sine wave (red curve) is sampled and quantized for PCM. The sine wave is sampled at regular intervals, shown as ticks on the x-axis. For each sample, one of the available values (ticks on the y-axis) is chosen by some algorithm (in this case, the floor function is used). This produces a fully discrete representation of the input signal (shaded area) that can be easily encoded as digital data for storage or manipulation. For the sine wave example at right, we can verify that the quantized values at the sampling moments are 7, 9, 11, 12, 13, 14, 14, 15, 15, 15, 14, etc. Encoding these values as binary numbers would result in the following set of nibbles: 0111, 1001, 1011, 1100, 1101, 1110, 1110, 1111, 1111, 1111, 1110, etc. These digital values could then be further processed or analyzed by a purpose-specific digital signal processor or general purpose CPU. Several Pulse Code Modulation streams could also be multiplexed into a larger aggregate data stream, generally for transmission of multiple streams over a single physical link. This technique is called time-division multiplexing, or TDM, and is widely used, notably in the modern public telephone system.

There are many ways to implement a real device that performs this task. In real systems, such a device is commonly implemented on a single integrated circuit that lacks only the clock necessary for sampling, and is generally referred to as an ADC (Analog-to-Digital converter). These devices will produce on their output a binary representation of the input whenever they are triggered by a clock signal, which would then be read by a processor of some sort.


Demodulation

To produce output from the sampled data, the procedure of modulation is applied in reverse. After each sampling period has passed, the next value is read and the output of the system is shifted instantaneously (in an idealized system) to the new value. As a result of these instantaneous transitions, the discrete signal will have a significant amount of inherent high frequency energy, mostly harmonics of the sampling frequency (see square wave). To smooth out the signal and remove these undesirable harmonics, the signal would be passed through analog filters that suppress artifacts outside the expected frequency range (i.e., greater than , the maximum resolvable frequency). Some systems use digital filtering to remove the lowest and largest harmonics. In some systems, no explicit filtering is done at all; as it's impossible for any system to reproduce a signal with infinite bandwidth, inherent losses in the system compensate for the artifacts — or the system simply does not require much precision. The sampling theorem suggests that practical PCM devices, provided a sampling frequency that is sufficiently greater than that of the input signal, can operate without introducing significant distortions within their designed frequency bands.

The electronics involved in producing an accurate analog signal from the discrete data are similar to those used for generating the digital signal. These devices are DACs (digital-to-analog converters), and operate similarly to ADCs. They produce on their output a voltage or current (depending on type) that represents the value presented on their inputs. This output would then generally be filtered and amplified for use.

      我来总结一下吧,这里的PCM指线性PCM,说线性是为了和下面的非线性作对比的。如果大家学习计算机组成原理,那就很好理解了,PCM其实就是音频经过ADC后的输出。但要注意,我们常用的ADC输入一般是0~5V,而对音频来说输入是可+也可-的,这也很好理解。我们常用的PCM一般是16位的。
      参考网页:
      http://en.wikipedia.org/wiki/Pulse-code_modulation
二、G.711
G.711 is an ITU-T standard for audio companding. It is primarily used in telephony. The standard was released for usage in 1972.
G.711 represents logarithmic pulse-code modulation (PCM) samples for signals of voice frequencies, sampled at the rate of 8000 samples/second.
Types

There are two main compression algorithms defined in the standard, the ?-law algorithm (used in North America & Japan) and A-law algorithm (used in Europe and the rest of the world). Both are logarithmic, but A-law was specifically designed to be simpler for a computer to process. The standard also defines a sequence of repeating code values which defines the power level of 0 dB.

The ?-law and A-law algorithms encode 14-bit and 13-bit signed linear PCM samples (respectively) to logarithmic 8-bit samples. Thus, the G.711 encoder will create a 64 kbit/s bitstream for a signal sampled at 8 kHz.

G.711, also known as Pulse Code Modulation (PCM), is a very commonly used waveform codec. G.711 uses a sampling rate of 8,000 samples per second, with the tolerance on that rate 50 parts per million (ppm). Non-uniform quantization with 8 bits is used to represent each sample, resulting in a 64 kbit/s bit rate. There are two slightly different versions; μ-law, which is used primarily in North America, and A-law, which is in use in most other countries outside North America. G.711 μ-law tends to give more resolution to higher range signals while G.711 A-law provides more quantization levels at lower signal levels. When using μ-law G.711 in networks where suppression of the all 0 character signal is required, the character signal corresponding to negative input values between decision values numbers 127 and 128 should be 00000010 and the value at the decoder output is -7519. The corresponding decoder output value number is 125.


G.711 A-Law

A-law encoding thus takes a 13-bit signed linear audio sample as input and converts it to an 8 bit value as follows:

Linear input codeCompressed code
s0000000wxyza...s000wxyz
s0000001wxyza...s001wxyz
s000001wxyzab...s010wxyz
s00001wxyzabc...s011wxyz
s0001wxyzabcd...s100wxyz
s001wxyzabcde...s101wxyz
s01wxyzabcdef...s110wxyz
s1wxyzabcdefg...s111wxyz

Where s is the sign bit. So for example, 1000000010101111 maps to 10001010 (according to the first row of the table), and 0000000110101111 maps to 00011010 (according to the second).
This can be seen as a floating point number with 4 bits of mantissa and 3 bits of exponent.
In addition, the standard specifies that all resulting even bits are inverted before the octet is transmitted. This is to provide plenty of 0/1 transitions to facilitate the clock recovery process in the PCM receivers. Thus, a silent A-law encoded PCM channel has the 8 bit samples coded 0x55 instead of 0x00 in the octets (or 0xD5 if the sign bit happens to be set), and a silent μ-law encoded PCM has 0xFF in the 8 bit samples.
Note that the ITU define bit 1 to have the value 128 and bit 8 to have the value 1.
The more widely accepted convention has bit 7 = 128 and bit 0 = 1.
Note that when data is sent over E0 (G.703), MSB (signbit) is sent first and LSB is sent last.


      这个我们也来理解理解,无非就是说,为了只表示语音,用16位取样精度太浪费空间了,用8位就够了, 不过直接用8位取样效果又太差,然后就有人来研究,原来人对小信号敏感一点,这样,就有人想出一个非线性的转换,能把16Bit的最大值65535转换成8位的最大值255的,注意这是一个非线性转换,对小的信号描述的详细点,对大的信号则描述的粗略一点。这样,就可以用8位比较清楚的记录下来语音了。真聪明!JRTPLIB@Conference DIY视频会议系统 五、PCM 和G.711编码相关 - 加菲 -  .
      这个转换用图来表示就如右图,但如果真按公式来算的话,那计算量就太大的(别认为计算机算得快就不为它考虑)所以就有人规定了能完成如右图这种转换的编码方式。这也就我们常说的A率(a law)和U率(u law)(看到上面那个表了吗,就这么转)。为什么有两种?两个人规定的就有两种呀,如果让我也规定一下就有三种了JRTPLIB@Conference DIY视频会议系统 五、PCM 和G.711编码相关 - 加菲 -  .。其中a law最通用。
      参考网页:
      http://telecom.tbi.net/digpcm.htm
      http://en.wikipedia.org/wiki/G.711
      http://www.lincoln.edu/math/rmyrick/ComputerNetworks/InetReference/127.htm
      http://en.wikipedia.org/wiki/G.711



------------------------------------------------------------------------------------------------------------------------------------


JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 

转自  http://wmnmtm.blog.163.com/blog/static/3824571420115401552469/


这是JRTPLIB@Conference系列的第六部《G.711编码事例程序》,本系列的主要工作是实现一个基于JRTPLIB的,建立在RTP组播基础上的多媒体视频会议系统。这只是一个实验系统,用于学习JRTPLIB、RTP、和多媒体相关的编程,不是一个完善的软件工程。而且,我只会在业余的时间出于兴趣写一写。有志同道合的朋友可以通过tinnal@136.com这个邮箱或博客回复(推荐)和我交流。
      上一部《JRTPLIB@Conference DIY视频会议系统 五、PCM 和G.711编码相关》
      这一部我们来做个实验,就是把用windows录音机录下来的"PCM 8.000 kHz, 16 位, 单声道"WAV文件转换成为我们要用的8位8000Hz a-law格式PCM。要注意的是录音机默认的方式是PCM 44.100 kHz, 16 位, 立体声,我们不想去进行采样频率的更改,因为这个要进行插值,而且也没必要,因为我们写软件时采样频率我们是可以更改的。所以我们要先把录音另为"PCM 8.000 kHz, 16 位, 单声道"格式。

一、WAV格式
      虽然会议系统完成后我们能直接向声卡拿到PCM数据,但毕竟我们现在拿到手的是WAV文件,我们要识别这种格式的头文件。下面是一编转自其它网站的《WAV 格式详解》(有一定修改)
1、综述
    WAVE文件作为多媒体中使用的声波文件格式之一,它是以RIFF格式为标准的。RIFF是英文Resource Interchange File Format的缩写,每个WAVE文件的头四个字节便是“RIFF”。
    WAVE文件是由若干个Chunk组成的。按照在文件中的出现位置包括:RIFF WAVE Chunk, Format Chunk, Fact Chunk(可选), Data Chunk。具体见下图:

------------------------------------------------
|             RIFF WAVE Chunk                  |
|             ID  = 'RIFF'                     |
|             RiffType = 'WAVE'                |
------------------------------------------------
|             Format Chunk                     |
|             ID = 'fmt '                      |
------------------------------------------------
|             Fact Chunk(optional)             |
|             ID = 'fact'                      |
------------------------------------------------
|             Data Chunk                       |
|             ID = 'data'                      |
------------------------------------------------
            图1   Wav格式包含Chunk示例

    其中除了Fact Chunk外,其他三个Chunk是必须的。每个Chunk有各自的ID,位于Chunk最开始位置,作为标示,而且均为4个字节。并且紧跟在ID后面的是Chunk大小(去除ID和Size所占的字节数后剩下的其他字节数目),4个字节表示,低字节表示数值低位,高字节表示数值高位。下面具体介绍各个Chunk内容。
PS:
    所有数值表示均为低字节表示低位,高字节表示高位。

2、具体介绍
RIFF WAVE Chunk
    ==================================
    |       |所占字节数|  具体内容   |
    ==================================
    | ID    |  4 Bytes |   'RIFF'    |
    ----------------------------------
    | Size  |  4 Bytes |             |
    ----------------------------------
    | Type  |  4 Bytes |   'WAVE'    |
    ----------------------------------
            图2  RIFF WAVE Chunk

    以'FIFF'作为标示,然后紧跟着为size字段,该size是整个wav文件大小减去ID和Size所占用的字节数,即FileLen - 8 = Size。然后是Type字段,为'WAVE',表示是wav文件。

Format Chunk
    ====================================================================
    |               |   字节数  |              具体内容                |
    ====================================================================
    | ID            |  4 Bytes  |   'fmt '                             |
    --------------------------------------------------------------------
    | Size          |  4 Bytes  | 数值为16或18,18则最后又附加信息     |
    --------------------------------------------------------------------  ----
    | FormatTag     |  2 Bytes  | 编码方式,一般为0x0001               |     |
    --------------------------------------------------------------------     |
    | Channels      |  2 Bytes  | 声道数目,1--单声道;2--双声道       |     |
    --------------------------------------------------------------------     |
    | SamplesPerSec |  4 Bytes  | 采样频率                             |     |
    --------------------------------------------------------------------     |
    | AvgBytesPerSec|  4 Bytes  | 每秒所需字节数                       |     |===> WAVE_FORMAT
    --------------------------------------------------------------------     |
    | BlockAlign    |  2 Bytes  | 数据块对齐单位(每个采样需要的字节数) |     |
    --------------------------------------------------------------------     |
    | BitsPerSample |  2 Bytes  | 每个采样需要的bit数                  |     |
    --------------------------------------------------------------------     |
    |               |  2 Bytes  | 附加信息(可选,通过Size来判断有无) |     |
    --------------------------------------------------------------------  ----
                            图3  Format Chunk

    以'fmt '作为标示。一般情况下Size为16,此时最后附加信息没有;如果为18,则最后多了2个字节的附加信息。主要由一些软件制成的wav格式中含有该2个字节的附加信息。
Fact Chunk
    ==================================
    |       |所占字节数|  具体内容   |
    ==================================
    | ID    |  4 Bytes |   'fact'    |
    ----------------------------------
    | Size  |  4 Bytes |   数值为4   |
    ----------------------------------
    | data  |  4 Bytes |             |
    ----------------------------------
            图4  Fact Chunk

    Fact Chunk是可选字段,一般当wav文件由某些软件转化而成,则包含该Chunk。
 

Data Chunk
    ==================================
    |       |所占字节数|  具体内容   |
    ==================================
    | ID    |  4 Bytes |   'data'    |
    ----------------------------------
    | Size  |  4 Bytes |             |
    ----------------------------------
    | data  |          |             |
    ----------------------------------
             图5 Data Chunk

    Data Chunk是真正保存wav数据的地方,以'data'作为该Chunk的标示。然后是数据的大小。紧接着就是wav数据。根据Format Chunk中的声道数以及采样bit数,wav数据的bit位置可以分成以下几种形式:
    ---------------------------------------------------------------------
    |   单声道  |    取样1    |    取样2    |    取样3    |    取样4    |
    |           |--------------------------------------------------------
    |  8bit量化 |    声道0    |    声道0    |    声道0    |    声道0    |
    ---------------------------------------------------------------------
    |   双声道  |          取样1            |           取样2           |
    |           |--------------------------------------------------------
    |  8bit量化 |  声道0(左)  |  声道1(右)  |  声道0(左)  |  声道1(右)  |
    ---------------------------------------------------------------------
    |           |          取样1            |           取样2           |
    |   单声道  |--------------------------------------------------------
    | 16bit量化 |    声道0    |  声道0      |    声道0    |  声道0      |
    |           | (低位字节)  | (高位字节)  | (低位字节)  | (高位字节)  |
    ---------------------------------------------------------------------
    |           |                         取样1                         |
    |   双声道  |--------------------------------------------------------
    | 16bit量化 |  声道0(左)  |  声道0(左)  |  声道1(右)  |  声道1(右)  |
    |           | (低位字节)  | (高位字节)  | (低位字节)  | (高位字节)  |
    ---------------------------------------------------------------------
                         图6 wav数据bit位置安排方式

3、小结
    因此,根据上述结构定义以及格式介绍,很容易编写相应的wav格式解析代码。这里具体的代码就不给出了。  


二、代码的实现 

      根据上面的格式规定,我们把它写成一头文件wav.h


 1 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  . #ifndef _WAV_H_
 2 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  . #define _WAV_H_
 3 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .
 4 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  . #include "types.h"
 5 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .
 6 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  . #pragma pack(1)
 7 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .
 8 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  . struct RIFF_HEADER
 9 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  . JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  . JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  . {
10 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .     U8        szRiffID[4];  // 'R','I','F','F'
11 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .     U32        dwRiffSize;
12 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .     U8        szRiffFormat[4]; // 'W','A','V','E'
13 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  . };
14 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .
15 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  . struct WAVE_FORMAT
16 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  . JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  . JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  . {
17 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .     U16        wFormatTag;
18 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .     U16        wChannels;
19 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .     U32        dwSamplesPerSec;
20 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .     U32        dwAvgBytesPerSec;
21 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .     U16        wBlockAlign;
22 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .     U16        wBitsPerSample;
23 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .     U16        pack;        //附加信息
24 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  . };
25 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  . struct FMT_BLOCK
26 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  . JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  . JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  . {
27 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .     U8        szFmtID[4]; // 'f','m','t',' '
28 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .     U32        dwFmtSize;
29 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .     struct    WAVE_FORMAT wavFormat;
30 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  . };
31 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .
32 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  . struct FACT_BLOCK
33 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  . JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  . JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  . {
34 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .     U8        szFactID[4]; // 'f','a','c','t'
35 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .     U32        dwFactSize;
36 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  . };
37 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .
38 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  . struct DATA_BLOCK
39 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  . JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  . JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  . {
40 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .     U8        szDataID[4]; // 'd','a','t','a'
41 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .     U32        dwDataSize;
42 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  . };
43 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .
44 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .
45 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  . #endif

      因为这是个简单的程序,我没有去规划,相就的WAV解码过程我放到main.c的main函数里做了,这是不应该的,请原谅JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .


  1 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  . JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  . /**//*******************************************************
  2 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  . *    这是配合我的博客《JRTPLIB@Conference DIY视频会议系统》
  3 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  . *    而写的一个阶段性实验。
  4 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  . *    作者:冯富秋 tinnal
  5 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  . *    邮箱:tinnal@163.com
  6 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  . *    博客:www.cnitblog.com/tinnal/
  7 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  . *    目期:2009-01-03
  8 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  . *    版本:1.00
  9 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  . *********************************************************/
 10 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .
 11 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  . #include "stdio.h"
 12 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  . #include "string.h"
 13 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  . #include "types.h"
 14 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  . #include "g711.h"
 15 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  . #include "wav.h"
 16 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .
 17 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  . struct RIFF_HEADER    riff_header;
 18 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  . struct FMT_BLOCK    fmt_block;
 19 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  . char   fack_block_buffer[20];        //20 should be enough
 20 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  . struct FACT_BLOCK    fact_block;
 21 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  . struct DATA_BLOCK    data_block;
 22 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .
 23 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  . int main(int argc, char **argv)
 24 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  . JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  . JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  . {
 25 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .     FILE *wav_in;
 26 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .     FILE *wav_out;
 27 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .     U32 i;
 28 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .     U8    has_fact_block =0;
 29 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .
 30 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .     unsigned char pcm_bytes[2];
 31 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .     short pcm;
 32 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .     unsigned char a_law;    
 33 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .
 34 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .     long file_pos;
 35 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .
 36 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .     if(argc != 3 )
 37 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  . JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .      JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  . {
 38 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .         printf("Usage:\n\t%s <intput file> <output file>\n", argv[0]);
 39 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .         exit(-1);
 40 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .     }
 41 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .
 42 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .     wav_in = fopen(argv[1],"rb");
 43 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .     if(wav_in == NULL)
 44 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  . JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .      JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  . {
 45 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .         printf("Can't open input file %s\n", argv[1]);
 46 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .         return (-1);
 47 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .     }
 48 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .
 49 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .     wav_out = fopen(argv[2], "wb");
 50 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .     if( wav_out == NULL)
 51 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  . JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .      JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  . {
 52 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .         printf("Can't open output file %s\n",argv[2]);
 53 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .         fclose(wav_in);
 54 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .         return(-1);
 55 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .     }
 56 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .     
 57 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .     file_pos = ftell(wav_in);
 58 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .
 59 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .     //Read RIFF_HEADER
 60 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .     fread(&riff_header, sizeof(struct RIFF_HEADER), 1, wav_in);
 61 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .     if(    memcmp(riff_header.szRiffID, "RIFF", 4) != 0 ||
 62 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .         memcmp(riff_header.szRiffFormat, "WAVE", 4) != 0 )
 63 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  . JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .      JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  . {
 64 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .         printf("No a vaild wave file!\n");
 65 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .         fclose(wav_in);
 66 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .         fclose(wav_out);
 67 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .         return(-1);
 68 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .     }
 69 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .     file_pos = ftell(wav_in);
 70 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .
 71 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .     //Read FMT_BLOCK
 72 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .     fread(&fmt_block, sizeof(struct FMT_BLOCK), 1, wav_in);
 73 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .     if(    memcmp(fmt_block.szFmtID, "fmt ", 4) !=0 ||
 74 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .         fmt_block.dwFmtSize != 18 ||
 75 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .         fmt_block.wavFormat.wFormatTag != 0x1 ||
 76 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .         fmt_block.wavFormat.wChannels != 0x1 ||
 77 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .         fmt_block.wavFormat.dwSamplesPerSec != 8000 ||
 78 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .         fmt_block.wavFormat.wBitsPerSample != 16)
 79 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  . JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .      JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  . {
 80 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .         printf("Sorry this is only test program,\n"
 81 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .             "we only support follow format,\n"
 82 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .             "\t 1. Format:        linear PCM \n"
 83 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .             "\t 2. Samples Rate:  8000 KHz \n"
 84 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .             "\t 3. Channels:      one channel \n"
 85 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .             "\t 4. BitsPerSample: 16 \n");
 86 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .         fclose(wav_in);
 87 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .         fclose(wav_out);
 88 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .         return(-1);
 89 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .     }
 90 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .     
 91 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .     file_pos = ftell(wav_in);
 92 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .
 93 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .     //Try to read FACT_BLOCK
 94 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .     file_pos = ftell(wav_in);
 95 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .     fread(&fact_block, sizeof(struct FACT_BLOCK), 1, wav_in);
 96 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .     if( memcmp(fact_block.szFactID, "fact", 4) == 0 )
 97 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  . JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .      JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  . {    
 98 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .         has_fact_block =1;
 99 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .         fread(&fack_block_buffer, fact_block.dwFactSize, 1, wav_in);
100 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .     }
101 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .     else
102 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .         fseek(wav_in, file_pos, SEEK_SET);
103 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .     
104 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .     fread(&data_block, sizeof(struct DATA_BLOCK), 1, wav_in);
105 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .     if (memcmp(data_block.szDataID, "data", 4) != 0)
106 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  . JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .      JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  . {
107 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .         printf("OOh what error?\n");
108 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .         fclose(wav_in);
109 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .         fclose(wav_out);
110 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .         return(-1);
111 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .     }
112 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .
113 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .     //Change the wave header to write
114 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .     riff_header.dwRiffSize                    -=    data_block.dwDataSize/2 ;
115 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .     
116 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .     fmt_block.wavFormat.wFormatTag            =    0x06;
117 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .     fmt_block.wavFormat.wChannels            =    0x01;
118 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .     fmt_block.wavFormat.dwSamplesPerSec        =    8000;
119 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .     fmt_block.wavFormat.dwAvgBytesPerSec    =    8000;
120 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .     fmt_block.wavFormat.wBlockAlign            =    0x01;
121 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .     fmt_block.wavFormat.wBitsPerSample        =    0x08;
122 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .
123 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .     data_block.dwDataSize                    -=    data_block.dwDataSize/2 ;
124 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .
125 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .     //Write wave file header
126 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .     fwrite(&riff_header, sizeof(struct RIFF_HEADER), 1, wav_out);
127 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .     fwrite(&fmt_block, sizeof(struct FMT_BLOCK), 1, wav_out);
128 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .     if(has_fact_block == 1) 
129 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  . JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .      JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  . {
130 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .         fwrite(&fact_block, sizeof(struct FACT_BLOCK), 1, wav_out);
131 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .         fwrite(&fack_block_buffer, fact_block.dwFactSize, 1, wav_out);
132 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .     }
133 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .     fwrite(&data_block, sizeof(struct DATA_BLOCK), 1, wav_out);
134 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .
135 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .     //Convert pcm data to a-low data  and  write wav file.
136 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .     for(i =0; i< data_block.dwDataSize; i++)
137 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  . JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .      JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  . {
138 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .         pcm_bytes[0] = (U8) fgetc(wav_in);
139 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .         pcm_bytes[1] = (U8) fgetc(wav_in);
140 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .         pcm = *(short *)&pcm_bytes;
141 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .
142 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .         a_law     = ALawEncode((int)pcm);
143 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  . //        a_law     = linear2alaw((int)pcm);
144 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .         fputc(a_law, wav_out);
145 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .     }
146 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .     fclose(wav_in);
147 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .     fclose(wav_out);
148 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .     
149 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .     printf("Finish!\n");
150 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .     return 0;
151 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  . }
152 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .

      整个文件基本都是在为WAV文件格式服务而非我们的核心工作--G.711编码。唉~,我也不想。这里在面进行G.711编码的就是ALawEncode函数。这个函数定义在g711.c里件里,这个文件函数一些我认为比较有用的函数。我们这是只把ALawEncode这个函数拿出来。 


 1 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  . // JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  . 省略的代码
 2 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  . unsigned char ALawEncode(int pcm16)
 3 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  . JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  . JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  . {
 4 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .     int p = pcm16;
 5 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .     unsigned a;  // A-law value we are forming
 6 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .     if(p<0)
 7 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  . JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .      JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  . {
 8 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .         // -ve value
 9 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .         // Note, ones compliment is used here as this keeps encoding symetrical
10 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .         // and equal spaced around zero cross-over, (it also matches the standard).
11 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .         p = ~p;
12 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .         a = 0x00; // sign = 0
13 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .     }
14 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .     else
15 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  . JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .      JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  . {
16 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .         // +ve value
17 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .         a = 0x80; // sign = 1
18 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .     }
19 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .     
20 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .     // Calculate segment and interval numbers
21 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .     p >>= 4;
22 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .     if(p>=0x20)
23 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  . JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .      JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  . {
24 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .         if(p>=0x100)
25 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  . JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .          JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  . {
26 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .             p >>= 4;
27 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .             a += 0x40;
28 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .         }
29 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .         if(p>=0x40)
30 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  . JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .          JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  . {
31 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .             p >>= 2;
32 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .             a += 0x20;
33 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .         }
34 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .         if(p>=0x20)
35 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  . JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .          JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  . {
36 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .             p >>= 1;
37 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .             a += 0x10;
38 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .         }
39 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .     }
40 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .     // a&0x70 now holds segment value and 'p' the interval number
41 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .     
42 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .     a += p;  // a now equal to encoded A-law value
43 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .     
44 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  .     return a^0x55;    // A-law has alternate bits inverted for transmission
45 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  . }
46 JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  . // JRTPLIB@Conference DIY视频会议系统 六、G.711编码事例程序 - 加菲 -  . 省略的代码



























评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值