RTMP学习(八)rtmpdump源码阅读(3)初始化与URL解析

时间:2022-02-04 19:35:25

初始化与URL解析


初始化


    初始化实际就是创建rtmp对象实例,然后初始化各个成员。

// 创建rtmp对象,设置rtmp实例的属性
void
RTMP_Init(RTMP *r)
{
#ifdef CRYPTO
if (!RTMP_TLS_ctx)
RTMP_TLS_Init();
#endif

memset(r, 0, sizeof(RTMP));
r->m_sb.sb_socket = -1;
r->m_inChunkSize = RTMP_DEFAULT_CHUNKSIZE;
r->m_outChunkSize = RTMP_DEFAULT_CHUNKSIZE;
r->m_nBufferMS = 30000;
r->m_nClientBW = 2500000;
r->m_nClientBW2 = 2;
r->m_nServerBW = 2500000;
r->m_fAudioCodecs = 3191.0;
r->m_fVideoCodecs = 252.0;
r->Link.timeout = 30;
r->Link.swfAge = 30;
r->Link.CombineConnectPacket = TRUE;
r->Link.ConnectPacket = FALSE;
}




URL解析


    URL解析的目的是把URL中的各个成分提取出来,为接下来连接的建立做准备。

    以 rtmp://live.hkstv.hk.lxdns.com/live/hks为例子,它经过解析之后,就可以得到下面各个部分:

        协议:rtmp
        host:live.hkstv.hk.lxdns.com/live/hks
        path:hks
        application:live/hks

/*
** 解析rtmp的URL
*/
int RTMP_ParseURL(const char *url, int *protocol, AVal *host, unsigned int *port,
AVal *playpath, AVal *app)
{
char *p, *end, *col, *ques, *slash;

RTMP_Log(RTMP_LOGDEBUG, "Parsing...");

// 设置默认的协议:rtmp
*protocol = RTMP_PROTOCOL_RTMP;
*port = 0;
playpath->av_len = 0;
playpath->av_val = NULL;
app->av_len = 0;
app->av_val = NULL;

/* Old School Parsing */

/* look for usual :// pattern */
p = strstr(url, "://");
if (!p) {
RTMP_Log(RTMP_LOGERROR, "RTMP URL: No :// in url!");
return FALSE;
}
{
int len = (int)(p - url);

// 解析协议头
/*
** 支持的协议有:
** rtmp
** rtmpe
** rtmpt
** rtmps
** rtmpte
** rtmpts
** rtmfp
*/
if (len == 4 && strncasecmp(url, "rtmp", 4) == 0)
*protocol = RTMP_PROTOCOL_RTMP;
else if (len == 5 && strncasecmp(url, "rtmpt", 5) == 0)
*protocol = RTMP_PROTOCOL_RTMPT;
else if (len == 5 && strncasecmp(url, "rtmps", 5) == 0)
*protocol = RTMP_PROTOCOL_RTMPS;
else if (len == 5 && strncasecmp(url, "rtmpe", 5) == 0)
*protocol = RTMP_PROTOCOL_RTMPE;
else if (len == 5 && strncasecmp(url, "rtmfp", 5) == 0)
*protocol = RTMP_PROTOCOL_RTMFP;
else if (len == 6 && strncasecmp(url, "rtmpte", 6) == 0)
*protocol = RTMP_PROTOCOL_RTMPTE;
else if (len == 6 && strncasecmp(url, "rtmpts", 6) == 0)
*protocol = RTMP_PROTOCOL_RTMPTS;
else {
RTMP_Log(RTMP_LOGWARNING, "Unknown protocol!\n");
goto parsehost;
}
}

RTMP_Log(RTMP_LOGDEBUG, "Parsed protocol: %d", *protocol);

parsehost:
/* let's get the hostname */
p += 3;

/* check for sudden death */
if (*p == 0) {
RTMP_Log(RTMP_LOGWARNING, "No hostname in URL!");
return FALSE;
}

end = p + strlen(p);
col = strchr(p, ':');
ques = strchr(p, '?');
slash = strchr(p, '/');

// 解析主机名
{
int hostlen;
if (slash)
hostlen = slash - p;
else
hostlen = end - p;
if (col && col - p < hostlen)
hostlen = col - p;

if (hostlen < 256) {
host->av_val = p;
host->av_len = hostlen;
RTMP_Log(RTMP_LOGDEBUG, "Parsed host : %.*s", hostlen, host->av_val);
}
else {
RTMP_Log(RTMP_LOGWARNING, "Hostname exceeds 255 characters!");
}

p += hostlen;
}

// 解析端口号
/* get the port number if available */
if (*p == ':') {
unsigned int p2;
p++;
p2 = atoi(p);
if (p2 > 65535) {
RTMP_Log(RTMP_LOGWARNING, "Invalid port number!");
}
else {
*port = p2;
}
}

if (!slash) {
RTMP_Log(RTMP_LOGWARNING, "No application or playpath in URL!");
return TRUE;
}
p = slash + 1;

// 解析app
{
/* parse application
*
* rtmp://host[:port]/app[/appinstance][/...]
* application = app[/appinstance]
*/

char *slash2, *slash3 = NULL;
int applen, appnamelen;

slash2 = strchr(p, '/');
if (slash2)
slash3 = strchr(slash2 + 1, '/');

applen = end - p; /* ondemand, pass all parameters as app */
appnamelen = applen; /* ondemand length */

if (ques && strstr(p, "slist=")) { /* whatever it is, the '?' and slist= means we need to use everything as app and parse plapath from slist= */
appnamelen = ques - p;
}
else if (strncmp(p, "ondemand/", 9) == 0) {
/* app = ondemand/foobar, only pass app=ondemand */
applen = 8;
appnamelen = 8;
}
else { /* app!=ondemand, so app is app[/appinstance] */
if (slash3)
appnamelen = slash3 - p;
else if (slash2)
appnamelen = slash2 - p;

applen = appnamelen;
}

app->av_val = p;
app->av_len = applen;
RTMP_Log(RTMP_LOGDEBUG, "Parsed app : %.*s", applen, p);

p += appnamelen;
}

if (*p == '/')
p++;

// 解析path
if (end - p) {
AVal av = { p, end - p };
RTMP_ParsePlaypath(&av, playpath);
}

return TRUE;
}