RTMP_ParseUrl 源代码分析,
// rtsp://192.168.10.100 : 8888 / vlc/avatar.mp4 \0 // p col slash end /* 可以记录一种含有杂质的字符串中任何一种数据类型 例如记录url中从哪开始(用av_val区别)到哪结束(用av_len区别)属于主机号,属于应用名 ,av_val 记录主机号的首地址,av_len记录主机号的长度,这样设置结构体的原因 主要是因为这种情况: 192.168.10.100:8888, 即av_val开始的字符串中会有干扰字符串,在这里 的就是:8888,我们使用av_len就可以具体指定出,哪段字符是主机号 typedef struct AVal { char *av_val; int av_len; } AVal; */ 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..."); *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); 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; //如果slash != 0, 则主机号 == 第一个反斜杠前的内容,否则如果一个url中没有反斜杠,则从p开始到 //url结尾的\0之前的字符,全都表示主机号(这里的主机号把端口号也考虑进去了,区分主机号和端口号 //的工作在下一个if语句中处理) if(slash) hostlen = slash - p; else hostlen = end - p; //如果url中存在冒号(只有存在端口号才会有冒号),则真正的主机号应该是冒号前的字符 直到 p指针 //col : 用来防止 col = strchr(p,':') 返回null情况 //col - p < hostlen 主要是防止 col - p == hostlen 即eg:119.75.218.77:,这种情况还是使用默认端口号 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!"); } //指向主机号192.168.10.100后的第一个字符,例如在上面的例子中指的就是‘:’ p+=hostlen; } /* get the port number if available */ if(*p == ':') { unsigned int p2; p++; //atoi 会从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; { /* parse application * * rtmp://host[:port]/app[/appinstance][/...] * application = app[/appinstance] */ char *slash2, *slash3 = NULL, *slash4 = NULL; int applen, appnamelen; slash2 = strchr(p, '/'); if(slash2) slash3 = strchr(slash2+1, '/'); if(slash3) slash4 = strchr(slash3+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(slash4) appnamelen = slash4-p; else 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++; if (end-p) { AVal av = {p, end-p}; RTMP_ParsePlaypath(&av, playpath); } return TRUE; }