ortp定时器源码分析

ortp定时器源码分析

ortp中的定时器模块仅仅在数据收发的调度器中有被使用,所以非常简单。由于要跨平台所以定时器的代码实现都是调用了各个平台上的原生定时器接口。本文主要基于windows平台实现进行分析。

架构

定时器是一个结构体,结构体中含有初始化,等待超时,销毁三个函数指针,使用的时候通过调用这几个函数来使用。还有一个周期成员但是其实并没有任何作用,真正的周期已经写死在代码里无法修改。

结构体

RtpTimer

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;
  • interval是一个timeval类型的时间间隔,表示定时器的周期。
    其他三个可以看出是函数指针,因为ortp是一个跨平台库,所以这三个函数指针分别指向本平台的三个定时器函数。
  • timer_init函数是初始化函数,需要在使用前调用一次。
  • timer_uninit函数是销毁函数,需要在使用结束后调用一次。
  • timer_do是一个阻塞函数,调用后会阻塞interval所设定的时间。

函数实现

window平台函数实现

#ifdef ORTP_WINDOWS_DESKTOP

#include <windows.h>
#include <mmsystem.h>


MMRESULT timerId;
HANDLE   TimeEvent;
int      late_ticks;


static DWORD posix_timer_time;
static DWORD offset_time;


#define TIME_INTERVAL           50
#define TIME_RESOLUTION         10
#define TIME_TIMEOUT            100



void CALLBACK timerCb(UINT uID, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2)
{
        // Check timerId
        if (timerId == uID)
        {
                SetEvent(TimeEvent);
                posix_timer_time += TIME_INTERVAL;
        }
}


void win_timer_init(void)
{
        timerId = timeSetEvent(TIME_INTERVAL,10,timerCb,0,TIME_PERIODIC | TIME_CALLBACK_FUNCTION);
        TimeEvent = CreateEvent(NULL,FALSE,FALSE,NULL);

        late_ticks = 0;

        offset_time = GetTickCount();
        posix_timer_time=0;
}


void win_timer_do(void)
{
        DWORD diff;

        // If timer have expired while we where out of this method
        // Try to run after lost time.
        if (late_ticks > 0)
        {
                late_ticks--;
                posix_timer_time+=TIME_INTERVAL;
                return;
        }


        diff = GetTickCount() - posix_timer_time - offset_time;
        if( diff>TIME_INTERVAL && (diff<(1<<31)))
        {
                late_ticks = diff/TIME_INTERVAL;
                ortp_warning("we must catchup %i ticks.",late_ticks);
                return;
        }

        WaitForSingleObject(TimeEvent,TIME_TIMEOUT);
        return;
}


void win_timer_close(void)
{
    timeKillEvent(timerId); 
}



RtpTimer posix_timer={  0,
                        win_timer_init,
                        win_timer_do,
                        win_timer_close,
                        {0,TIME_INTERVAL * 1000}};

定时器在不同平台各有实现,此处分析windows平台上的实现。从代码可以看出,定时器调用了windows的多媒体定时器接口。可以看到定时器所用到的变量都是全局的,说明这个定时器是全局唯一的。
posix_timer_time记录了定时器运行的毫秒数
offset_time记录了定时器启动时的时间(开机后的毫秒数)
late_ticks是定时器发生异常需要追赶的次数,通常情况是不会异常的。
timerIdwindows多媒体定时器ID
TimeEvent用于唤醒的事件
posix_timer是存储了本平台上实现的相关定时器函数指针的结构体
win_timer_init函数用来启动定时器,函数创建了周期50毫秒windows多媒体定时器和一个事件,并记录了此时的时间。此时定时器就已经开始运行并定期回调了。
timerCb函数是windwos多媒体定时器的回调函数,每50毫秒就激活事件并把时间数记录加50。
win_timer_do函数首先检查是否需要追赶,然后计算当前时间减去定时器开始的时间再减去定时器运行的时长和50毫秒周期比较以检查是否定时器出现异常,如果都没有异常就等待事件被激发。如果定时器运行正常那么在外部不断调用此函数每次会等待到50毫秒的周期后返回。
注意这里使用了GetTickCount函数获取时间,众所周知GetTickCount获取的是开机的时长,并且只有4个字节,所以开机49.7天后这个函数获取的值就会清零重新开始,所以这个定时器运行到开机49.7天之后会出问题,如果是长时间不关机的服务器程序可一定得注意这点。
win_timer_close函数销毁定时器,注意此函数只关闭了windows多媒体定时器,并没有销毁TimeEvent事件,所以在多次反复的调用win_timer_initwin_timer_close创建销毁定时器后会导致句柄泄漏。不过定时器其实并没有销毁的必要,不建议销毁它。

linux平台函数实现

static struct timeval orig,cur;
static uint32_t posix_timer_time=0;     /*in milisecond */

void posix_timer_init()
{
    posix_timer.state=RTP_TIMER_RUNNING;
    ortp_gettimeofday(&orig,NULL);
    posix_timer_time=0;
}




void posix_timer_do()
{
    int diff,time;
    struct timeval tv;
    ortp_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
        ortp_gettimeofday(&cur,NULL);
        time=((cur.tv_usec-orig.tv_usec)/1000 ) + ((cur.tv_sec-orig.tv_sec)*1000 );
    }
    posix_timer_time+=POSIXTIMER_INTERVAL/1000;

}

void posix_timer_uninit()
{
    posix_timer.state=RTP_TIMER_STOPPED;
}

RtpTimer posix_timer={  0,
                        posix_timer_init,
                        posix_timer_do,
                        posix_timer_uninit,
                        {0,POSIXTIMER_INTERVAL}};

可以看到linux平台下的实现更简单,连和操作系统相关的定时器都没有,直接在定时器的执行函数里用select函数进行了睡眠。

rtp_timer_set_interval

void rtp_timer_set_interval(RtpTimer *timer, struct timeval *interval)
{
    if (timer->state==RTP_TIMER_RUNNING){
        ortp_warning("Cannot change timer interval while it is running.\n");
        return;
    }
    timer->interval.tv_sec=interval->tv_sec;
    timer->interval.tv_usec=interval->tv_usec;
}

此函数是用来设置定时器的周期的,但是根据前文可以知道定时器周期是不能更改的。所以这个函数看起来修改了周期其实并没有任何作用,所以这个函数永远不会被使用。估计是作者挖的坑忘了填。

总结

从上文可以看出,这个ortp的定时器功能非常少,只有一个全局唯一的对象posix_timer,并且定时器周期默认初始化为50毫秒不能更改,也不能在多个地方共用。但是因为这个定时器只为ortp中的数据收发调度器模块服务,并不在其他地方使用,所以这么简陋也是可以理解的。
不过windows实现的定时器因为使用了GetTickCount函数不能运行超过开机49.7天这点要注意。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 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、付费专栏及课程。

余额充值