oRTP源码分析

oRTP源码分析


前言

本文主要是想在阅读oRTP协议栈时,为了以后的回忆,做些笔录。



一、AVProfile 模块

1.1 Pt的总结:

引用:http://en.wikipedia.org/wiki/RTP_audio_video_profile

RTP/AVP audio and video payload types

Payload type (PT)

Name

Type

No. of channels

Clock rate (Hz)

Description

References

0

PCMU

audio

1

8000

ITU-T G.711PCM µ-LawAudio 64 kbit/s

RFC 3551

1

reserved (previously 1016)

audio

1

8000

reserved, previously CELPAudio 4.8 kbit/s

RFC 3551,previously RFC 1890

2

reserved (previously G721)

audio

1

8000

reserved, previously ITU-T G.721ADPCM Audio32 kbit/s

RFC 3551,previously RFC 1890

3

GSM

audio

1

8000

European GSMFull Rate Audio 13 kbit/s (GSM 06.10)

RFC 3551

4

G723

audio

1

8000

ITU-T G.723.1

RFC 3551

5

DVI4

audio

1

8000

IMAADPCM Audio32 kbit/s

RFC 3551

6

DVI4

audio

1

16000

IMAADPCM 64 kbit/s

RFC 3551

7

LPC

audio

1

8000

Experimental LinearPredictive Coding Audio

RFC 3551

8

PCMA

audio

1

8000

ITU-T G.711 PCM A-LawAudio 64 kbit/s

RFC 3551

9

G722

audio

1

8000

ITU-T G.722Audio

RFC 3551- Page 14

10

L16

audio

2

44100

Linear PCM16-bit Stereo Audio 1411.2 kbit/s,[2][3][4]uncompressed

RFC 3551,Page 27

11

L16

audio

1

44100

Linear PCM 16-bit Audio 705.6 kbit/s, uncompressed

RFC 3551,Page 27

12

QCELP

audio

1

8000

Qualcomm CodeExcited Linear Prediction

RFC 2658, RFC3551

13

CN

audio

1

8000

Comfortnoise. Payload type used with audio codecs that do notsupport comfort noise as part of the codec itself such as G.711,G.722.1,G.722, G.726,G.727, G.728,GSM 06.10,Siren, andRTAudio.

RFC 3389

14

MPA

audio

1

90000

MPEG-1 orMPEG-2 AudioOnly

RFC 3551, RFC2250

15

G728

audio

1

8000

ITU-T G.728Audio 16 kbit/s

RFC 3551

16

DVI4

audio

1

11025

IMAADPCM

RFC 3551

17

DVI4

audio

1

22050

IMA ADPCM

RFC 3551

18

G729

audio

1

8000

ITU-T G.729and G.729a

RFC 3551,Page 20

25

CELB

video

1

90000

Sun'sCellB Video Encoding[5]

RFC 2029

26

JPEG

video

1

90000

JPEG Video

RFC 2435

28

NV

video

1

90000

XeroxPARC's Network Video (nv)[6]

RFC 3551,Page 32

31

H261

video

1

90000

ITU-T H.261Video

RFC 4587

32

MPV

video

1

90000

MPEG-1 and MPEG-2 Video

RFC 2250

33

MP2T

audio/video

1

90000

MPEG-2 transportstream Video

RFC 2250

34

H263

video

 

90000

H.263 video,first version (1996)

RFC 3551, RFC2190

35 - 71

unassigned

    

RFC 3551,Page 32

72 - 76

Reserved for RTCP conflict avoidance

N/A

 

N/A

 

RFC 3551,Page 32

77 - 95

unassigned

    

RFC 3551,Page 32

dynamic

H263-1998

video

 

90000

H.263 video,second version (1998)

RFC 3551, RFC4629, RFC 2190

dynamic

H263-2000

video

 

90000

H.263 video,third version (2000)

RFC 4629

dynamic (or profile)

H264

video

 

90000

H.264 video(MPEG-4 Part 10)

RFC 6184,previously RFC 3984

dynamic (or profile)

theora

video

 

90000

Theora video

draft-barbato-avt-rtp-theora-01

dynamic

iLBC

audio

1

Internet lowBitrate Codec 13.33 or 15.2 kbit/s

RFC 3951

dynamic

PCMA-WB

audio

 

16000

ITU-T G.711.1,A-law

RFC 5391

dynamic

PCMU-WB

audio

 

16000

ITU-T G.711.1,µ-law

RFC 5391

dynamic

G718

audio

 

32000

ITU-T G.718

draft-ietf-avt-rtp-g718-03

dynamic

G719

audio

(various)

48000

ITU-T G.719

RFC 5404

dynamic

G7221

audio

 

16 or 32 kHz

ITU-T G.722.1

RFC 5577

dynamic

G726-16

audio

1

8000

ITU-T G.726audio with 16 kbit/s

RFC 3551

dynamic

G726-24

audio

1

8000

ITU-T G.726 audio with 24 kbit/s

RFC 3551

dynamic

G726-32

audio

1

8000

ITU-T G.726 audio with 32 kbit/s

RFC 3551

dynamic

G726-40

audio

1

8000

ITU-T G.726 audio with 40 kbit/s

RFC 3551

dynamic

G729D

audio

1

8000

ITU-T G.729Annex D

RFC 3551

dynamic

G729E

audio

1

8000

ITU-T G.729Annex E

RFC 3551

dynamic

G7291

audio

 

(various)

ITU-T G.729.1

RFC 4749

dynamic

GSM-EFR

audio

1

8000

ITU-T GSM-EFR(GSM 06.60)

RFC 3551

dynamic

GSM-HR-08

audio

1

8000

ITU-T GSM-HR(GSM 06.20)

RFC 5993

dynamic (or profile)

AMR

audio

(various)

8000

AdaptiveMulti-Rate audio

RFC 4867

dynamic (or profile)

AMR-WB

audio

(various)

16000

AdaptiveMulti-Rate Wideband audio (ITU-T G.722.2)

RFC 4867

dynamic (or profile)

AMR-WB+

audio

1, 2 or omit

72000

ExtendedAdaptive Multi Rate – WideBand audio

RFC 4352

dynamic (or profile)

vorbis

audio

(various)

from 8 kHz to 192 kHz

RTP Payload Format for VorbisEncoded Audio

RFC 5215

dynamic (or profile)

opus

audio

1, 2

48000 (the actual clock rate is signaled inside the payload)

RTP Payload Format for OpusSpeech and Audio Codec

draft

dynamic (or profile)

speex

audio

1

8000, 16000 or 32000

RTP Payload Format for the SpeexCodec

RFC 5574

dynamic (96-127)

mpa-robust

audio

 

90000

A More Loss-Tolerant RTP Payload Format for MP3Audio

RFC 5219

dynamic (or profile)

MP4A-LATM

audio

 

90000 or others

RTP Payload Format for MPEG-4Audio

RFC 6416(previously RFC3016)

dynamic (or profile)

MP4V-ES

video

 

90000 or others

RTP Payload Format for MPEG-4Visual

RFC 6416(previously RFC3016)

dynamic (or profile)

mpeg4-generic

audio/video

 

90000 or other

RTP Payload Format for Transport of MPEG-4Elementary Streams

RFC 3640

dynamic

VP8

video

 

90000

RTP Payload Format for Transport of VP8 Streams

draft-ietf-payload-vp8-08

dynamic

L8

audio

(various)

(various)

Linear PCM8-bit audio with 128 offset

RFC 3551Section 4.5.10 and Table 5

dynamic

DAT12

audio

(various)

8000, 11025, 16000, 22050, 24000, 32000, 44100, 48000 orothers

IEC 61119 12-bit nonlinear audio

RFC 3190Section 3

dynamic

L16

audio

(various)

8000, 11025, 16000, 22050, 24000, 32000, 44100, 48000 orothers

Linear PCM16-bit audio

RFC 3551Section 4.5.11, RFC2586

dynamic

L20

audio

(various)

8000, 11025, 16000, 22050, 24000, 32000, 44100, 48000 orothers

Linear PCM20-bit audio

RFC 3190Section 4

dynamic

L24

audio

(various)

8000, 11025, 16000, 22050, 24000, 32000, 44100, 48000 orothers

Linear PCM24-bit audio

RFC 3190Section 4

RFC 3551 listsdetails of the codec,or a reference for the details is provided. Payload identifiers96–127 are reserved for payloads defined dynamically during asession. The minimum payload support is defined as 0 (PCMU) and 5(DVI4). The document recommends dynamically assigned port numbers,although 5004 and 5005 have been registered for use of the profileand can be used instead. The standard also describes the process ofregistering new payload types with IANA.


H.264 可以填(96.



1.2 源码分析

这部分代码比较好理解,实现主要在avprofle.cpayloadtype.hrtpprofile.h,rtpprofile.c中。



struct _PayloadType
{
        int type; /**< one of PAYLOAD_* macros*/
        int clock_rate; /**< rtp clock rate*/
        char bits_per_sample;   /* in case of continuous audio data */
        char *zero_pattern;
        int pattern_length;
        /* other useful information for the application*/
        int normal_bitrate;     /*in bit/s */
        char *mime_type; /**<actually the submime, ex: pcm, pcma, gsm*/
        int channels; /**< number of channels of audio */
        char *recv_fmtp; /* various format parameters for the incoming stream */
        char *send_fmtp; /* various format parameters for the outgoing stream */
        int flags;
        void *user_data;
};

这里定义出PayloadType的基本的元素,具体变量的意义看代码注释。

变量 recv_fmtp/send_fmtp ,是用来保存SDP 的参数。



/**
 * The RTP profile is a table RTP_PROFILE_MAX_PAYLOADS entries to make the matching
 * between RTP payload type number and the PayloadType that defines the type of
 * media.
**/
struct _RtpProfile
{
        char *name;
        PayloadType *payload[RTP_PROFILE_MAX_PAYLOADS];
};
typedef struct _RtpProfile RtpProfile;



RtpProfile av_profile; 是一个全局的变量。

这里定义一个Payload的集合,然后调用rtp_profile_set_payload(...)函数,把格式话好的playload赋值到这个集合中,这是在用户调用ortp_init()时完成的。未初始化的可以调用rtp_profile_set_payload()来在应用层设置。



二、oRTP中的eventsignal模块

2.1 Signal的实现

	应用层可以调用 rtp_session_signal_connect(...)函数来绑定一个signal 和一个callback函数。当协议栈遇到某一事件时 就会调用rtp_signal_table_emit_x(...) 来向应用层报告。这里的实现思想也不难,主要就是回调函数的原理。

应用层 调用rtp_session_new(),那么就会调用rtp_session_init().在这个初始化函数中初始化了singnal_table

struct_RtpSession 结构体中定义了

        RtpSignalTable on_ssrc_changed;
        RtpSignalTable on_payload_type_changed;
        RtpSignalTable on_telephone_event_packet;
        RtpSignalTable on_telephone_event;
        RtpSignalTable on_timestamp_jump;
        RtpSignalTable on_network_error;
        RtpSignalTable on_rtcp_bye;
        struct _OList *signal_tables;

	分别表示RTP ssrc 变化,pt变化等事件的发生。
	typedef void (*RtpCallback)(struct _RtpSession *, ...);
	struct _RtpSignalTable
	{
        RtpCallback callback[RTP_CALLBACK_TABLE_MAX_ENTRIES];
        unsigned long user_data[RTP_CALLBACK_TABLE_MAX_ENTRIES];
        struct _RtpSession *session;
        const char *signal_name;
        int count;
	};

这里需要注意 一个struct_OList*signal_tables;的变量,在调用rtp_signal_table_init()时会把这些signale table 加入到一个list当中,这是为了后面应用层在添加事件时方便查寻。

见代码:

	int
	rtp_session_signal_connect (RtpSession * session, const char *signal_name,
                            RtpCallback cb, unsigned long user_data)
	{
        OList *elem;
        for (elem=session->signal_tables;elem!=NULL;elem=o_list_next(elem)){
                RtpSignalTable *s=(RtpSignalTable*) elem->data;
                if (strcmp(signal_name,s->signal_name)==0){
                        return rtp_signal_table_add(s,cb,user_data);
                }
        }
        ortp_warning ("rtp_session_signal_connect: inexistant signal %s",signal_name);
        return -1;
	}


函数rtp_session_signal_connectsession->signal_tables中先根据signal_name来找到具体的一个RtpSignalTable,然后再在这个表中调节事件的回调函数。







2.2 Event 实现

Event的实现似乎和signal功能差不多,但实现却不一样,至于为什么这样实现,我们先不考虑,就看看作者到是是如何实现这一过程的吧。初看Event的实现有点搞不明白事件到底是如何发送和接受,尤其是时间如何被接受。后来结合linphone的应用程序才有点搞明白。



struct_RtpSession 的结构中有个成员变量struct_OList*eventqs;这个List用来存放OrtpEvQueue的头指针,结构如下图。







/**

 * Register an event queue.
 * An application can use an event queue to get informed about various RTP events.
**/
void rtp_session_register_event_queue(RtpSession *session, OrtpEvQueue *q){
        session->eventqs=o_list_append(session->eventqs,q);
}
void rtp_session_unregister_event_queue(RtpSession *session, OrtpEvQueue *q){
        session->eventqs=o_list_remove(session->eventqs,q);
}



eventOrtpEvQueue是在应用层定义,通过rtp_session_register_event_queue()注册到oRTP协议栈中。协议栈通过rtp_session_dispatch_event()session->eventqs中的每一个OrtpEvQueue分发消息,应用层中,需要自己调用ortp_ev_queue_get()来获得消息,并处理。



消息类型有

	/* type is one of the following*/
	#define ORTP_EVENT_STUN_PACKET_RECEIVED         1
	#define ORTP_EVENT_PAYLOAD_TYPE_CHANGED         2
	#define ORTP_EVENT_TELEPHONE_EVENT              3
	#define ORTP_EVENT_RTCP_PACKET_RECEIVED         4 /**<when a RTCP packet is 																received from far end */
	#define ORTP_EVENT_RTCP_PACKET_EMITTED          5 /**<fired when oRTP decides 												to send an automatic RTCP SR or RR */
	#define ORTP_EVENT_ZRTP_ENCRYPTION_CHANGED      6
	#define ORTP_EVENT_ZRTP_SAS_READY               7
	#define ORTP_EVENT_ICE_CHECK_LIST_PROCESSING_FINISHED   8
	#define ORTP_EVENT_ICE_SESSION_PROCESSING_FINISHED      9
	#define ORTP_EVENT_ICE_GATHERING_FINISHED               10
	#define ORTP_EVENT_ICE_LOSING_PAIRS_COMPLETED           11
	#define ORTP_EVENT_ICE_RESTART_NEEDED                   12





ORTP_EVENT_RTCP_PACKET_RECEIVED消息接收到后,应用层可以根据RTCP包做流量控制。



typedefmblk_tOrtpEvent;

消息体的结构就是个mblk_t的类型,这个结构块中存放了

typedefunsignedlongOrtpEventType;

	struct _OrtpEventData{
        mblk_t *packet; /* most events are associated to a received packet */
        RtpEndpoint *ep;
        ortpTimeSpec ts;
        union {
                int telephone_event;
                int payload_type;
                bool_t zrtp_stream_encrypted;
                struct _ZrtpSas{
                        char sas[5]; // 4 characters
                        bool_t verified;
                } zrtp_sas;
                OrtpSocketType socket_type;
                bool_t ice_processing_successful;
        } info;
	};

两个数据类型。









三、定时器RtpTimer

RtpTimer所涉及的文件有rtptimer.c posixtimer.crtptimer.h .

RtpTimer就是一个状态和函数指针的结构体。具体的函数在posixtimer.c中赋值。

//这里是个函数的指针类型;
typedef void (*RtpTimerFunc)(void);
        
struct _RtpTimer
{
        int state;
#define RTP_TIMER_RUNNING 1
#define RTP_TIMER_STOPPED 0
        RtpTimerFunc timer_init;
        RtpTimerFunc timer_do;
        RtpTimerFunc timer_uninit;
        struct timeval interval;
};
typedef struct _RtpTimer RtpTimer;





	RtpTimer posix_timer; 这是个全局的变量作为协议栈的定时器。





/*
  定义RtpTimer , 全局变量
*/
RtpTimer posix_timer={  0,
                        posix_timer_init,
                        posix_timer_do,
                        posix_timer_uninit,
                        {0,POSIXTIMER_INTERVAL}};





最需要具体理解下的就是posix_timer_do()函数,这个函数实现了精确的定时处理。

Timer的实现可以由下图表示:





 

posix_timer_time 是安自己的步调向前走,每次posix_timer_do()被调用,函数就会比较实际时间和posix_timer_time的差距,如果diff0,就表示时间到了,如何不为0,就利用 select(0,NULL,NULL,NULL,&tv);做延时。 对照下面的代码可以很好理解了。



void posix_timer_do()
{
        int diff,time;
        struct timeval tv;
        gettimeofday(&cur,NULL);
        time=((cur.tv_usec-orig.tv_usec)/1000 ) + ((cur.tv_sec-orig.tv_sec)*1000 );
        if ( (diff=time-posix_timer_time)>50){
                ortp_warning("Must catchup %i miliseconds.",diff);
        }
        while((diff = posix_timer_time-time) > 0)
        {
                tv.tv_sec = diff/1000;
                tv.tv_usec = (diff%1000)*1000;
#if     defined(_WIN32) || defined(_WIN32_WCE)
        /* this kind of select is not supported on windows */
                Sleep(tv.tv_usec/1000 + tv.tv_sec * 1000);
#else
                select(0,NULL,NULL,NULL,&tv);
#endif
                gettimeofday(&cur,NULL);
                time=((cur.tv_usec-orig.tv_usec)/1000 ) + ((cur.tv_sec-orig.tv_sec)*1000 );
        }
        posix_timer_time+=POSIXTIMER_INTERVAL/1000;
        
}

时间单位
 (s)     second
毫秒(ms)   millisecond
微秒 (us)  microsecond
纳秒 (ns)
皮秒 (ps)
飞秒 (fs)
阿托秒(简称阿秒)(as)







四、RtpScheduler模块



RtpScheduler主要是在上一节中提到的RtpTimer的基础上实现的一个系统的调度处理,实现了类似linuxselect()syscall 的功能。要明白RtpShcedule的工作原理,先看看几个重要的数据结构的关系。




调度器的工作看起来比较复杂,但慢慢分析还是可以理解里面的原理的。调度器是在一个void*rtp_scheduler_schedule(void* psched)的线程中实现的。他以一个恒定的速度调用rtp_session_process

来轮训所有的rtp_session。在这个rtp_session_process中又通过

        struct {
                RtpProfile *profile;
                int pt;
                unsigned int ssrc;
                WaitPoint wp;
                int telephone_events_pt;/* the payload type used for telephony events */
        } snd,rcv;



这个变量wp来控制 rtp_session_recvm_with_trtp_session_sendm_with_t 的速度。

对几个时间变量的理解:

(1)sched->time_:在调度器时间轴的时间值,从0 开始,安sched->timer_inc向前运行。

(2)session->rtp.snd_ts_offset:第一次发送数据的时间戳值;

(3)session->rtp.snd_time_offset:第一发送数据时的在调度器时间轴上的时间值;

session->rtp.snd_ts_offsetsession->rtp.snd_time_offset是为了计算packet_time,也就是把发送数据时的时间都统一到调度器的时间轴上来做比较(比较使用宏TIME_IS_STRICTLY_NEWER_THAN, 大于)








图中T1-T0 = T2-T1 =Tn-T(n-1) 表示sched 在匀速的向前。

图中t 0t1t2表示packet_time的时间

图中黄色的部分为记录集的状态

	sched 还通过 sched->unblock_select_cond变量来控制了 session_set_select的速度。
	从以上分析可以看出调度器 分别控制着 数据发送和接受 和select 的速度。所有sched的颗粒度决定了
	协议栈运行速度的快慢。







其他:

1. oRTPUDP也使用了connectsyscall, 这样使得UDP的效率更高。

UDP调用CONNECT
在末连接UDP套接口上给两个数据报调用函数sendto导致内核执行下列六步:
1.连接套接口;
2.输出第一个数据报
3.断开套接口连接;
4.连接套接口,
5.输出第二个数据报;
6.断开套接口连接
已连接套接口发送两个数据报的导致内核执行如下步骤;
1.连接套接口;
2.输出第一个数据报;
3.输出第二个数据报。
对同一套接口发送时,耗时减少1/3





  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
本季课程通过移植ORTP库并调用ORTP库函数来实现H.264裸流数据的网络传输,并且在Windows中安装VLC播放器,并在VLC中通过配置文件的方式来解析ORTP发送的裸流实现视频实时预览。本季课程的核心是ORTP协议的讲解,ORTP库的移植、部署和调用,VLC软件的用法讲解和配置文件讲解,Wireshark网络抓包工具的用法讲解,实时视频流传输和解析的体验和编程实现。随着通信行业发展,网速越来越快,网络也从文本时代发展越过语音时代到了现在视频时代,“优酷、爱奇艺”、“微视频”、“直播”等的出现也是视频逐步成为主流媒体的证据和表现。航拍、视频监控、刷脸过关检测、汽车ADAS系统等应用也是视频在主流行业中的应用,因此视频的采集、编解码、传输、识别等技术变得越来越有价值,涌现出了“海康威视”、“大华股份”、“深圳英飞拓”等一批明星企业,名扬海内外,动辄市值几百亿。同时在芯片级,国产华为海思HI35XX系列视频编解码方案也逐步取代进口芯片(如TI、安霸)成为主流方案。视频行业技术含量高、难度大、学习周期长、发展变化快而资料少,因此行业比较缺人、工资较高。如海康威视,普通高校硕士研究生应届进入年薪普遍高于15-20万,在嵌入式linux领域也算高工资技术方向了。本项目是朱老师及其团队推出的一个嵌入式linux领域重量级企业级实战项目,选用华为海思HI3518E方案,结合OV9712/AR0130 Sensor实现图像采集和H.264编码压缩,并通过ethernet和WIFI,以socket实时流和RTSP等方式,实现720P/960P高清视频传输。本项目共分11季,从海思SDK开发环境搭建,到sample程序讲解、SDK中API函数解析,到H.264编解码、RTSP流媒体传输、MP4文件打包,到图像IQ调试、图像识别等视频领域高阶内容,可以说从零基础入手,对图像采集、编解码、网络传输、图像存储和识别做了全方位的详细讲解和代码分析,是目前市面上**一套系统讲解图像和视频技术的视频课程。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值