1、URL格式介绍
“rtsp”和“rtspu”表示要通过 RTSP 协议来定位网络资源。 RTSP URL 的语法和语义如下所示:
rtsp_URL = "rtsp:" | "rtspu:" ) "//" host [ ":" port ] [ abs_path ]
host = <合法的 Internet 主机域名或 IP 地址(用十进制数及点组成),如 192.168.0.64
abs_path 的定义如下所示:
abs_path = "/" rel_pathrel_path = [ path ] [ ";" params ] [ "?" query ]
path = fsegment *( "/" segment )fsegment = 1*pchar
segment = *pchar
params = param *( ";" param )param = *( pchar | "/" )
scheme = 1*( ALPHA | DIGIT | "+" | "-" | "." )net_loc = *( pchar | ";" | "?" )
query = *( uchar | reserved )
fragment = *( uchar | reserved )
pchar = uchar | ":" | "@" | "&" | "=" | "+"
uchar = unreserved | escapeunreserved = ALPHA | DIGIT | safe | extra | national
escape = "%" HEX HEXreserved = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+"
extra = "!" | "*" | "'" | "(" | ")" | ","safe = "$" | "-" | "_" | "."
unsafe = CTL | SP | <"> | "#" | "%" | "<" | ">"national = <any OCTET excluding ALPHA, DIGIT,
reserved, extra, safe, and unsafe>
权威的 URL 语法及语义信息请参见 RFC1738[4]和 RFC1808[9]。
[注意]:段(fragment)和询问(query)标识符在这时没有明确的定义,需要到 RTSP服务器上解释。
rtsp 要求使用可靠协议(Internet 的 TCP 协议)发出命令,而 rtspu 则使用不可靠协议(Internet 的 UDP 协议)。如果端口为空或没指定,则缺省为 80 端口。对于rtsp_URI 来说,拥有被请求的资源的服务器主机通过侦听该端口的 TCP 连接(rtsp)或 UDP 包(rtspu)来接收该 URI 请求。只要可能,应尽量避免的在 URL 中直接使用IP 地址。(请参考 RFC1924)文本媒体标识符使用 URL 中的字符集及转义规则(参考RFC1738)来标识一个表示(presentation)与单个流(stream)。URL 可以用于单个流或者多个流的集合,比如表示(presentation)。因此,请求(request)可以用于整个表示(presentation)或表示中的单个流。注意,有些请求方法仅能用于流而不能用于表示,反之亦然。例如:RTSP URL:rtsp://media.example.com:554/twister/audiotrack
也可以是这样 RTSP URL:rtsp://media.example.com:554/twister
标识了由音频和视频流组成的 twister 表示(presentation)。
这并没有给出 URL 中相关流的标准方法。表示描述定义了表示中的层次关系以及单独流的 URL。如一个表示描述可能将一个流命名为 a.mov,而将整个表示命名为 b.mov。RTSP URL 的路径组成对客户端来说不可见并且也并没有给出服务器的具体文件系统结构。只需进行简单替换后,表示描述同样可以用于非 RTSP 媒体控制协议。
2、URL解析
下面的代码示例用于解析RTSP的URL,以获得有用的信息。代码为本人自己实现,可能会存在一些问题,望指正。代码中用到了几个字符串处理换函数,如strchr()、strncpy()、strtoul()等。
URL解析代码示例:
static int parsingRTSPURL(char const* url, char* username, char* password, char* address,int* portNum, char* path)
{
// Parse the URL as "rtsp://[<username>[:<password>]@]<server-address-or-name>[:<port>][/<path>]"
uint32_t const prefixLength = 7;
char const* from = &url[prefixLength];
char const* tmpPos;
if ((tmpPos = strchr(from, '@')) != NULL) {
// We found <username> (and perhaps <password>).
char const* usernameStart = from;
char const* passwordStart = NULL;
char const* p = tmpPos;
if ((tmpPos = strchr(from, ':')) != NULL && tmpPos < p) {
passwordStart = tmpPos;
uint32_t passwordLen = p - passwordStart;
strncpy(password, passwordStart, passwordLen);
password[passwordLen] = '\0'; //Set the ending character.
}
uint32_t usernameLen = 0;
if (passwordStart != NULL) {
usernameLen = tmpPos - usernameStart;
} else {
usernameLen = p - usernameStart;
}
strncpy(username, usernameStart, usernameLen);
username[usernameLen] = '\0'; //Set the ending character.
from = p + 1; // skip the '@'
}
const char* pathStart = NULL;
if ((tmpPos = strchr(from, '/')) != NULL) {
uint32_t pathLen = strlen(tmpPos + 1); //Skip '/'
strncpy(path, tmpPos + 1, pathLen + 1);
pathStart = tmpPos;
}
// Next, will parse the address and port.
tmpPos = strchr(from, ':');
if (tmpPos == NULL) {
if (pathStart == NULL) {
uint32_t addressLen = strlen(from);
strncpy(address, from, addressLen + 1); //Already include '\0'
} else {
uint32_t addressLen = pathStart - from;
strncpy(address, from, addressLen);
address[addressLen] = '\0'; //Set the ending character.
}
*portNum = 554; // Has not the specified port, and will use the default value
} else if (tmpPos != NULL) {
uint32_t addressLen = tmpPos - from;
strncpy(address, from, addressLen);
address[addressLen] = '\0'; //Set the ending character.
*portNum = strtoul(tmpPos + 1, NULL, 10);
}
return 1;
}