蜗牛的家
男儿当自强
posts - 48,  comments - 21,  trackbacks - 0
     摘要: UML基础知识   UML简介 在80年代末至90年代中,对面向对象分析与设计方法的研究发展到一个高潮。但是,诸多流派在思想和术语上有很多不同的提法,在术语、概念上的运用也各不相同,需要一种统一的符号来描述面向对象的分析和设计活动。UML应运而生。它不仅统一了Booch、Rumbaugh和Jacobson的表示方法,而且有进一步的发展,最终成为大众所共同接受的标准建模语言。统一建模...  阅读全文
posted @ 2011-04-27 14:24 黑色天使 阅读(961) | 评论 (0)编辑 收藏
所谓Lambda,简单的说是快速的小函数生成.
在STL的算法中很多地方需要提供一个函数对象或仿函数如for_each
for_each(v.begin(), v.end(), op());    //原格式如此
如果需要不用的算法就需要些不同的函数对象,但是引用了万能的lambda后效果就不同了,效果如下
for_each(v.begin(), v.end(), _1=2);    //_1=2是一个仿函数,通过重载=实现
需要的操作一目了然,简单分析下for_each第三个参数需要的是一个函数或仿函数,所以_1=2必然产生的是一个仿函数,大致可以推出是重载了=实现的产生仿函数,那么真正的操作还需要一个封装,即需要两个类实现,第一个类大致如下
struct place_holder
{
    
//重载需要的算法操作
    template <typename R>
    op
<R> operator=(R i)
    {
        
return op<R>(i);
    }
};
模板使得这个结构可以传入任何类型的参数,通过重载=操作内部返回了一个仿函数,具体的操作由一下的仿函数实现
//仿函数,即重载了()操作的类
template <typename T>
struct op
{
    op(T i): _i(i) {}
    T 
operator()(T &i)
    {
        
return i = _i;
    }
    T _i;
};
这个仿函数将传入的引用参数进行了赋值操作,实现了最终的操作.
以上的代码实现=操作如果需要其他操作则重载相应的操作例如+=
依次类推占位类实现+=并通过仿函数可以实现+=的操作以下是完成的代码
// lambda.cpp : 定义控制台应用程序的入口点。
//

#include 
"stdafx.h"
#include 
<vector>
#include 
<algorithm>

using namespace std;

//仿函数,即重载了()操作的类
template <typename T>
struct op
{
    op(T i): _i(i) {}
    T 
operator()(T &i)
    {
        
return i = _i;
    }
    T _i;
};
template 
<typename T>
struct op1
{
    op1(T i):_i(i){}
    T 
operator()(T &i)
    {
        
return i + _i;
    }
    T _i;
};

//占位符
struct place_holder
{
    
//重载需要的算法操作
    template <typename R>
    op
<R> operator=(R i)
    {
        
return op<R>(i);
    }
    template 
<typename R>
    op1
<R> operator+=(R i)
    {
        
return op1<R>(i);
    }
};

place_holder _1;

int _tmain(int argc, _TCHAR* argv[])
{
    vector
<int> v;
    v.push_back(
1);
    v.push_back(
2);
    v.push_back(
3);

    
//for_each(v.begin(), v.end(), op());    //原格式如此
    for_each(v.begin(), v.end(), _1=2);    //_1=2是一个仿函数,通过重载=实现

    
return 0;
}


posted @ 2011-03-22 23:47 黑色天使 阅读(491) | 评论 (0)编辑 收藏
#include "stdafx.h"
#include 
<algorithm>
#include 
<iostream>
#include 
<string>
#include 
<vector>

using namespace std;

struct Person
{
    Person(
const string& name)
        : name_(name)
    {}

    
string Name()
    {
        
return name_;
    }

    
void SetName(string name)
    {
        name_ 
= name;
    }

    
string name_;
};

template 
<typename R, typename T, typename Arg>
class simple_binder
{
public:
    
explicit simple_binder(R (T::*pfn)(Arg), const Arg& arg)
        : pfn_(pfn)
        , arg_(arg)
    {}

    R 
operator()(T& t)
    {
        
return (t.*pfn_)(arg_);
    }
private:
    R (T::
*pfn_)(Arg);
    Arg arg_;
};

template 
<typename R, typename T, typename Arg>
simple_binder
<R, T, Arg>
simple_bind( R (T::
*pfn)(Arg), const Arg& arg)
{
    
return simple_binder<R, T, Arg>(pfn, arg);
}

int main()
{
    Person person(
"Ralph");

    
//smimple_bind生成一个仿函数类,这个类构造时赋值了arg
    
//遇到(person)时,调用这个仿函数类重载的()操作即
    
//t.*pfn(arg)
    
//又回归为一个函数,不过参数可以自己控制了,娃哈哈
    simple_bind(&Person::SetName, string("Martin"))(person);
    cout 
<< person.Name() << endl;
}

posted @ 2011-03-22 23:46 黑色天使 阅读(606) | 评论 (0)编辑 收藏

计算机彩色显示器显示色彩的原理与彩色电视机一样,都是采用R(Red)、G(Green)、B(Blue)相加混色的原理:通过发射出三种不同强度的电子束,使屏幕内侧覆盖的红、绿、蓝磷光材料发光而产生色彩。这种色彩的表示方法称为RGB色彩空间表示(它也是多媒体计算机技术中用得最多的一种色彩空间表示方法)。
根据三基色原理,任意一种色光F都可以用不同分量的R、G、B三色相加混合而成。

F = r [ R ] + g [ G ] + b [ B ]

其中,r、g、b分别为三基色参与混合的系数。当三基色分量都为0(最弱)时混合为黑色光;而当三基色分量都为k(最强)时混合为白色光。调整r、g、b三个系数的值,可以混合出介于黑色光和白色光之间的各种各样的色光。
那么YUV又从何而来呢?在现代彩色电视系统中,通常采用三管彩色摄像机或彩色CCD摄像机进行摄像,然后把摄得的彩色图像信号经分色、分别放大校正后得到RGB,再经过矩阵变换电路得到亮度信号Y和两个色差信号R-Y(即U)、B-Y(即V),最后发送端将亮度和色差三个信号分别进行编码,用同一信道发送出去。这种色彩的表示方法就是所谓的YUV色彩空间表示。
采用YUV色彩空间的重要性是它的亮度信号Y和色度信号U、V是分离的。如果只有Y信号分量而没有U、V分量,那么这样表示的图像就是黑白灰度图像。彩色电视采用YUV空间正是为了用亮度信号Y解决彩色电视机与黑白电视机的兼容问题,使黑白电视机也能接收彩色电视信号。
YUV与RGB相互转换的公式如下(RGB取值范围均为0-255):

Y = 0.299R + 0.587G + 0.114B
U = -0.147R - 0.289G + 0.436B
V = 0.615R - 0.515G - 0.100B

R = Y + 1.14V
G = Y - 0.39U - 0.58V
B = Y + 2.03U

在DirectShow中,常见的RGB格式有RGB1、RGB4、RGB8、RGB565、RGB555、RGB24、RGB32、ARGB32等;常见的YUV格式有YUY2、YUYV、YVYU、UYVY、AYUV、Y41P、Y411、Y211、IF09、IYUV、YV12、YVU9、 YUV411、YUV420等。作为视频媒体类型的辅助说明类型(Subtype),它们对应的GUID见表2.3。

表2.3 常见的RGB和YUV格式

GUID    格式描述
MEDIASUBTYPE_RGB1    2色,每个像素用1位表示,需要调色板
MEDIASUBTYPE_RGB4    16色,每个像素用4位表示,需要调色板
MEDIASUBTYPE_RGB8    256色,每个像素用8位表示,需要调色板
MEDIASUBTYPE_RGB565    每个像素用16位表示,RGB分量分别使用5位、6位、5位
MEDIASUBTYPE_RGB555    每个像素用16位表示,RGB分量都使用5位(剩下的1位不用)
MEDIASUBTYPE_RGB24    每个像素用24位表示,RGB分量各使用8位
MEDIASUBTYPE_RGB32    每个像素用32位表示,RGB分量各使用8位(剩下的8位不用)
MEDIASUBTYPE_ARGB32    每个像素用32位表示,RGB分量各使用8位(剩下的8位用于表示Alpha通道值)
MEDIASUBTYPE_YUY2    YUY2格式,以4:2:2方式打包
MEDIASUBTYPE_YUYV    YUYV格式(实际格式与YUY2相同)
MEDIASUBTYPE_YVYU    YVYU格式,以4:2:2方式打包
MEDIASUBTYPE_UYVY    UYVY格式,以4:2:2方式打包
MEDIASUBTYPE_AYUV    带Alpha通道的4:4:4 YUV格式
MEDIASUBTYPE_Y41P    Y41P格式,以4:1:1方式打包
MEDIASUBTYPE_Y411    Y411格式(实际格式与Y41P相同)
MEDIASUBTYPE_Y211    Y211格式
MEDIASUBTYPE_IF09    IF09格式
MEDIASUBTYPE_IYUV    IYUV格式
MEDIASUBTYPE_YV12    YV12格式
MEDIASUBTYPE_YVU9    YVU9格式

下面分别介绍各种RGB格式。

¨RGB1、RGB4、RGB8都是调色板类型的RGB格式,在描述这些媒体类型的格式细节时,通常会在BITMAPINFOHEADER数据结构后面跟着一个调色板(定义一系列颜色)。它们的图像数据并不是真正的颜色值,而是当前像素颜色值在调色板中的索引。以RGB1(2色位图)为例,比如它的调色板中定义的两种颜色值依次为0x000000(黑色)和0xFFFFFF(白色),那么图像数据001101010111…(每个像素用1位表示)表示对应各像素的颜色为:黑黑白白黑白黑白黑白白白…。

¨ RGB565使用16位表示一个像素,这16位中的5位用于R,6位用于G,5位用于B。程序中通常使用一个字(WORD,一个字等于两个字节)来操作一个像素。当读出一个像素后,这个字的各个位意义如下:
高字节              低字节
R R R R R G G G     G G G B B B B B
可以组合使用屏蔽字和移位操作来得到RGB各分量的值:

#define RGB565_MASK_RED    0xF800
#define RGB565_MASK_GREEN  0x07E0
#define RGB565_MASK_BLUE   0x001F
R = (wPixel & RGB565_MASK_RED) >> 11;   // 取值范围0-31
G = (wPixel & RGB565_MASK_GREEN) >> 5;  // 取值范围0-63
B =  wPixel & RGB565_MASK_BLUE;         // 取值范围0-31

¨ RGB555是另一种16位的RGB格式,RGB分量都用5位表示(剩下的1位不用)。使用一个字读出一个像素后,这个字的各个位意义如下:
高字节             低字节
X R R R R G G       G G G B B B B B       (X表示不用,可以忽略)
可以组合使用屏蔽字和移位操作来得到RGB各分量的值:

#define RGB555_MASK_RED    0x7C00
#define RGB555_MASK_GREEN  0x03E0
#define RGB555_MASK_BLUE   0x001F
R = (wPixel & RGB555_MASK_RED) >> 10;   // 取值范围0-31
G = (wPixel & RGB555_MASK_GREEN) >> 5;  // 取值范围0-31
B =  wPixel & RGB555_MASK_BLUE;         // 取值范围0-31

¨ RGB24使用24位来表示一个像素,RGB分量都用8位表示,取值范围为0-255。注意在内存中RGB各分量的排列顺序为:BGR BGR BGR…。通常可以使用RGBTRIPLE数据结构来操作一个像素,它的定义为:

typedef struct tagRGBTRIPLE {
BYTE rgbtBlue;    // 蓝色分量
BYTE rgbtGreen;   // 绿色分量
BYTE rgbtRed;     // 红色分量
} RGBTRIPLE;

¨ RGB32使用32位来表示一个像素,RGB分量各用去8位,剩下的8位用作Alpha通道或者不用。(ARGB32就是带Alpha通道的 RGB32。)注意在内存中RGB各分量的排列顺序为:BGRA BGRABGRA…。通常可以使用RGBQUAD数据结构来操作一个像素,它的定义为:

typedef struct tagRGBQUAD {
BYTE    rgbBlue;      // 蓝色分量
BYTE    rgbGreen;     // 绿色分量
BYTE    rgbRed;       // 红色分量
BYTE    rgbReserved;  // 保留字节(用作Alpha通道或忽略)
} RGBQUAD;

下面介绍各种YUV格式。YUV格式通常有两大类:打包(packed)格式和平面(planar)格式。前者将YUV分量存放在同一个数组中,通常是几个相邻的像素组成一个宏像素(macro-pixel);而后者使用三个数组分开存放YUV三个分量,就像是一个三维平面一样。表2.3中的YUY2到 Y211都是打包格式,而IF09到YVU9都是平面格式。(注意:在介绍各种具体格式时,YUV各分量都会带有下标,如Y0、U0、V0表示第一个像素的YUV分量,Y1、U1、V1表示第二个像素的YUV分量,以此类推。)

¨ YUY2(和YUYV)格式为每个像素保留Y分量,而UV分量在水平方向上每两个像素采样一次。一个宏像素为4个字节,实际表示2个像素。(4:2:2的意思为一个宏像素中有4个Y分量、2个U分量和2个V分量。)图像数据中YUV分量排列顺序如下:
Y0 U0 Y1 V0    Y2 U2 Y3 V2 …

¨ YVYU格式跟YUY2类似,只是图像数据中YUV分量的排列顺序有所不同:
Y0 V0 Y1 U0    Y2 V2 Y3 U2 …

¨ UYVY格式跟YUY2类似,只是图像数据中YUV分量的排列顺序有所不同:
U0 Y0 V0 Y1    U2 Y2 V2 Y3 …

¨ AYUV格式带有一个Alpha通道,并且为每个像素都提取YUV分量,图像数据格式如下:
A0 Y0 U0 V0    A1 Y1 U1 V1 …

¨ Y41P(和Y411)格式为每个像素保留Y分量,而UV分量在水平方向上每4个像素采样一次。一个宏像素为12个字节,实际表示8个像素。图像数据中YUV分量排列顺序如下:
U0 Y0 V0 Y1    U4 Y2 V4 Y3    Y4 Y5 Y6 Y8 …

¨ Y211格式在水平方向上Y分量每2个像素采样一次,而UV分量每4个像素采样一次。一个宏像素为4个字节,实际表示4个像素。图像数据中YUV分量排列顺序如下:
Y0 U0 Y2 V0    Y4 U4 Y6 V4 …

¨ YVU9格式为每个像素都提取Y分量,而在UV分量的提取时,首先将图像分成若干个4 x 4的宏块,然后每个宏块提取一个U分量和一个V分量。图像数据存储时,首先是整幅图像的Y分量数组,然后就跟着U分量数组,以及V分量数组。IF09格式与YVU9类似。

¨ IYUV格式为每个像素都提取Y分量,而在UV分量的提取时,首先将图像分成若干个2 x 2的宏块,然后每个宏块提取一个U分量和一个V分量。YV12格式与IYUV类似。

¨YUV411、YUV420格式多见于DV数据中,前者用于NTSC制,后者用于PAL制。YUV411为每个像素都提取Y分量,而UV分量在水平方向上每4个像素采样一次。YUV420并非V分量采样为0,而是跟YUV411相比,在水平方向上提高一倍色差采样频率,在垂直方向上以U/V间隔的方式减小一半色差采样。

//YUV转UYVY格式
void YUVtoUYVY(uint8_t *y_plane, uint8_t *u_plane, uint8_t *v_plane, int y_stride, 
                      
int uv_stride, OUT uint8_t *pDstBuf, int width, int height)
{
    
for (int row = 0; row < height; row = row + 1{
        
for (int col = 0; col < width; col=col + 2{
            pDstBuf[
0= u_plane[row/2 * uv_stride + col/2];
            pDstBuf[
1= y_plane[row * y_stride + col];
            pDstBuf[
2= v_plane[row/2 * uv_stride + col/2];
            pDstBuf[
3= y_plane[row * y_stride + col + 1];
            pDstBuf 
+= 4;
        }

    }

}

posted @ 2009-07-07 18:19 黑色天使 阅读(5530) | 评论 (0)编辑 收藏
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两次,当然,后面那次会失败,也就是说测试不了,要测?找两台机器,或用虚拟机),如果组播不满足,我们就要把组播变在单播,这时就要返复调用这个函数把其它组成员的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.

发送者报告(SR)

V| P| RC| PT=SR=200| LEN|


发送者SSRC (已关联)


NTP时间戳(高32位) SR_GetNTPTimestamp ()

 

NTP时间戳(低32位)


RTP时间戳 SR_GetRTPTimestamp () 

 


发送者分组计数器 SR_GetPacketCount()

 


发送者字节计数器 SR_GetByteCount ()

 


...(下面是这个发送者所发送的接收者报告,在下面和RR一起讨论)

 


附加信息:

这个源是否有发送发送者报告

SR_HasInfo ()

这个发送者报告接收的时间

SR_GetReceiveTime ()

以及以SR_Prev_开头的,获得倒数第二个发送者报告的信息。



接收者报告(RR)

V| P| RC| PT=SR=201| LEN|


 

SSRC1(第一个接收者报告块所关联的发送者) (已关联)

分组丢失率 | 丢失分组总数|

扩展的最高序号

间隔抖动

最新的发送者报告时间戳(LSR)

SR最新间隔(DLSR)

附加信息:
这个源是否有发送接收者报告
接收者报告接收时间
以及以RR_Prev_开头的,获得倒数第二个接收者报告的信息。
posted @ 2009-06-26 13:13 黑色天使 阅读(1395) | 评论 (0)编辑 收藏

YUV主要的采样格式

主要的采样格式有YCbCr 4:2:0YCbCr 4:2:2YCbCr 4:1:1 YCbCr 4:4:4。其中YCbCr 4:1:1 比较常用,其含义为:每个点保存一个 8bit 的亮度值(也就是Y), 2x2 个点保存一个 Cr Cb , 图像在肉眼中的感觉不会起太大的变化。所以, 原来用 RGB(R,G,B 都是 8bit unsigned) 模型, 4 个点需要 8x3=24 bites(如下图第一个图). 而现在仅需要 8+(8/4)+(8/4)=12bites, 平均每个点占12bites(如下图第二个图)。这样就把图像的数据压缩了一半。

    上边仅给出了理论上的示例,在实际数据存储中是有可能是不同的,下面给出几种具体的存储形式:

1    YUV 4:4:4

YUV三个信道的抽样率相同,因此在生成的图像里,每个象素的三个分量信息完整(每个分量通常8比特),经过8比特量化之后,未经压缩的每个像素占用3个字节。

下面的四个像素为: [Y0 U0 V0] [Y1 U1 V1] [Y2 U2 V2] [Y3 U3 V3]

存放的码流为: Y0 U0 V0 Y1 U1 V1 Y2 U2 V2 Y3 U3 V3

2   YUV 4:2:2

      每个色差信道的抽样率是亮度信道的一半,所以水平方向的色度抽样率只是4:4:4的一半。对非压缩的8比特量化的图像来说,每个由两个水平方向相邻的像素组成的宏像素需要占用4字节内存。

下面的四个像素为: [Y0 U0 V0] [Y1 U1 V1] [Y2 U2 V2] [Y3 U3 V3]

存放的码流为: Y0 U0 Y1 V1 Y2 U2 Y3 V3

映射出像素点为:[Y0 U0 V1] [Y1 U0 V1] [Y2 U2 V3] [Y3 U2 V3]

3   YUV 4:1:1

4:1:1的色度抽样,是在水平方向上对色度进行4:1抽样。对于低端用户和消费类产品这仍然是可以接受的。对非压缩的8比特量化的视频来说,每个由4个水平方向相邻的像素组成的宏像素需要占用6字节内存

下面的四个像素为: [Y0 U0 V0] [Y1 U1 V1] [Y2 U2 V2] [Y3 U3 V3]

存放的码流为: Y0 U0 Y1 Y2 V2 Y3

映射出像素点为:[Y0 U0 V2] [Y1 U0 V2] [Y2 U0 V2] [Y3 U0 V2]

4YUV4:2:0

     4:2:0并不意味着只有Y,Cb而没有Cr分量。它指得是对每行扫描线来说,只有一种色度分量以2:1的抽样率存储。进行隔行扫描,相邻的扫描行存储不同的色度分量,也就是说,如果一行是4:2:0的话,下一行就是4:0:2,再下一行是4:2:0...以此类推。对每个色度分量来说,水平方向和竖直方向的抽样率都是2:1,所以可以说色度的抽样率是4:1。对非压缩的8比特量化的视频来说,每个由2x222列相邻的像素组成的宏像素需要占用6字节内存。

下面八个像素为:[Y0 U0 V0] [Y1 U1 V1] [Y2 U2 V2] [Y3 U3 V3]

                [Y5 U5 V5] [Y6 U6 V6] [Y7U7 V7] [Y8 U8 V8]

存放的码流为:Y0 U0 Y1 Y2 U2 Y3

                     Y5 V5 Y6 Y7 V7 Y8

映射出的像素点为:[Y0 U0 V5] [Y1 U0 V5] [Y2 U2 V7] [Y3 U2 V7]

                  [Y5 U0 V5] [Y6 U0 V5] [Y7U2 V7] [Y8 U2 V7] 

对应AVPicture里面有data[4]和linesize[4]其中data是一个指向指针的指针(二级、二维指针),也就是指向视频数据缓冲区的首地址,而data[0]~data[3]是一级指针,可以用如下的图来表示:

data -->xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
        ^                ^              ^
        |                |              |
         data[0]      data[1]         data[2]

比如说,当pix_fmt=PIX_FMT_YUV420P时,data中的数据是按照YUV的格式存储的,也就是:

data -->YYYYYYYYYYYYYYUUUUUUUUUUUUUVVVVVVVVVVVV
^             ^            ^
|             |            |
data[0]    data[1]      data[2]

linesize是指对应于每一行的大小,为什么需要这个变量,是因为在YUV格式和RGB格式时,每行的大小不一定等于图像的宽度,对于RGB格式输出时,只有一个通道(bgrbgrbgr......)可用,即linesize[0],和data[0],so RGB24 : data[0] = packet rgb//bgrbgrbgr......

linesize[0] = width*3

其他的如data[1][2][3]与linesize[1][2][3]无任何意义.

而对于YUV格式输出时,有三个通道可用,即data[0][1][2],与linesize[0][1][2],而yuv格式对于运动估计时,需要填充padding(right, bottom),故:

linesize=width+padding size(16+16).
///////////////////////////////////////////////////////////////////////////////////////

   case PIX_FMT_YUV420P:
   case PIX_FMT_YUVJ420P:
   case PIX_FMT_RGB555:
    if (PIC_DIRECTION_0 == m_dwFilpPicDirection)
    {
     m_pYuvFrame->data [0] += m_pYuvFrame->linesize[0] *  m_pVCodecContext->height;
     //因为是隔行扫描U与V只有高度的一半
     m_pYuvFrame->data [1] += m_pYuvFrame->linesize[1] *  m_pVCodecContext->height/2;
     m_pYuvFrame->data [2] += m_pYuvFrame->linesize[2] *  m_pVCodecContext->height/2;
     m_pYuvFrame->linesize[0] = -m_pYuvFrame->linesize[0];
     m_pYuvFrame->linesize[1] = -m_pYuvFrame->linesize[1];
     m_pYuvFrame->linesize[2] = -m_pYuvFrame->linesize[2];
    }
    
    break;
   case PIX_FMT_YUVJ422P:
   case PIX_FMT_YUV422P:
   case PIX_FMT_YUYVJ422:
   case PIX_FMT_YUV411P:
   case PIX_FMT_YUYV422:  
    if (PIC_DIRECTION_0 == m_dwFilpPicDirection)
    {
     m_pYuvFrame->data [0] += m_pYuvFrame->linesize[0] *  m_pVCodecContext->height;
     m_pYuvFrame->data [1] += m_pYuvFrame->linesize[1] *  m_pVCodecContext->height;
     m_pYuvFrame->data [2] += m_pYuvFrame->linesize[2] *  m_pVCodecContext->height;
     m_pYuvFrame->linesize[0] = -m_pYuvFrame->linesize[0];
     m_pYuvFrame->linesize[1] = -m_pYuvFrame->linesize[1];
     m_pYuvFrame->linesize[2] = -m_pYuvFrame->linesize[2];
    }
    break;
   }
在FFMPEG中转换RGB时顺便颠倒图像的方向算法
posted @ 2009-06-08 15:23 黑色天使 阅读(3859) | 评论 (1)编辑 收藏
     摘要:   阅读全文
posted @ 2009-03-11 11:40 黑色天使 阅读(767) | 评论 (0)编辑 收藏
不经清贫难成人,
不经打击老天真,
自古英雄出炼狱,
从来富贵落凡尘,
醉生梦死谁成器,
破马长枪顶乾坤。
posted @ 2009-02-19 15:56 黑色天使 阅读(135) | 评论 (0)编辑 收藏
     摘要:   阅读全文
posted @ 2009-02-17 12:44 黑色天使 阅读(473) | 评论 (0)编辑 收藏
     摘要:   阅读全文
posted @ 2009-02-14 13:47 黑色天使 阅读(164) | 评论 (0)编辑 收藏
仅列出标题  下一页

<2018年12月>
2526272829301
2345678
9101112131415
16171819202122
23242526272829
303112345

常用链接

留言簿(2)

随笔分类

随笔档案

文章档案

搜索

  •  

最新评论

阅读排行榜

评论排行榜