📄 sdp_decode.c
字号:
if (mptr == NULL) {
if (sptr->control_string != NULL) {
/* Rtsp_Printf( "2nd control statement in media\n");
*/
return (-1);
}
sptr->control_string = strdup(lptr);
} else {
if (mptr->control_string != NULL) {
/* Rtsp_Printf( "2nd control statement in session\n");
*/
return (-1);
}
mptr->control_string = strdup(lptr);
}
break;
case 8:
if (sptr->etag != NULL) {
/* Rtsp_Printf( "2nd etag statement\n");
*/
return (-1);
}
sptr->etag = strdup(lptr);
break;
}
return (0);
}
/*
* This structure provides the information needed by the parsing
* engine in sdp_decode_parse_a. This function processes lines of
* the format a=<identifier>[:<options>].
* name - <identifier>
* len - sizeof(identifier) (saves on CPU time)
* have_colon - if a colon is necessary
* remove_spaces_after_colon - if colon is necessary, and we want
* to remove spaces before <option>. Do not use this if other character
* sets may come into play.
* parse_routine - routine to call if keyword matched. Return 0 if successful-
* -1 will save the whole "a=..." string.
* arg - value to pass to parse_routine
*/
static struct {
char *name;
uint32_t len;
int have_colon;
int remove_spaces_after_colon;
int (*parse_routine)(int arg, char *lptr,
session_desc_t *sptr, media_desc_t *mptr);
int arg;
} a_types[] =
{
{ "rtpmap", sizeof("rtpmap"), TRUE, TRUE, sdp_decode_parse_a_rtpmap, 0 },
{ "cat", sizeof("cat"), TRUE, TRUE, sdp_decode_parse_a_cat, 0 },
{ "fmtp", sizeof("fmtp"), TRUE, TRUE, sdp_decode_parse_a_fmtp, 0 },
{ "keywds", sizeof("keywds"), TRUE, FALSE, sdp_decode_parse_a_str, 0},
{ "tool", sizeof("tool"), TRUE, TRUE, sdp_decode_parse_a_str, 1},
{ "charset", sizeof("charset"), TRUE, TRUE, sdp_decode_parse_a_str, 2},
{ "sdplang", sizeof("sdplang"), TRUE, TRUE, sdp_decode_parse_a_str, 3},
{ "lang", sizeof("lang"), TRUE, TRUE, sdp_decode_parse_a_str, 4},
{ "type", sizeof("type"), TRUE, TRUE, sdp_decode_parse_a_str, 5},
{ "orient", sizeof("orient"), TRUE, TRUE, sdp_decode_parse_a_str, 6},
{ "control", sizeof("control"), TRUE, TRUE, sdp_decode_parse_a_str, 7},
{ "etag", sizeof("etag"), TRUE, TRUE, sdp_decode_parse_a_str, 8},
{ "recvonly", sizeof("recvonly"), FALSE, FALSE, sdp_decode_parse_a_bool, 0},
{ "sendrecv", sizeof("sendrecv"), FALSE, FALSE, sdp_decode_parse_a_bool, 1},
{ "sendonly", sizeof("sendonly"), FALSE, FALSE, sdp_decode_parse_a_bool, 2},
{ "ptime", sizeof("ptime"), TRUE, TRUE, sdp_decode_parse_a_int, 0 },
{ "quality", sizeof("quality"), TRUE, TRUE, sdp_decode_parse_a_int, 1},
{ "framerate", sizeof("framerate"), TRUE, TRUE, sdp_decode_parse_a_frame, 0},
{ "range", sizeof("range"), TRUE, TRUE, sdp_decode_parse_a_range, 0 },
{ NULL, 0, FALSE, FALSE, NULL },
};
/*
* sdp_decode_parse_a()
* decodes a= lines, or stores the complete string in media or session
* unparsed_a_lines list.
*/
static int sdp_decode_parse_a (char *lptr,
char *line,
session_desc_t *sptr,
media_desc_t *mptr)
{
int ix;
int errret;
int parsed;
char *after;
ix = 0;
errret = 0;
parsed = FALSE;
/*
* go through above array, looking for a complete match
*/
while (a_types[ix].name != NULL) {
if (strncmp(lptr,
a_types[ix].name,
a_types[ix].len - 1) == 0) {
after = lptr + a_types[ix].len - 1;
if (!(isspace(*after) ||
*after == ':' ||
*after == '\0')) {
/* partial match - not good enough*/
continue;
}
parsed = TRUE;
/*
* Have a match. If specified, look for colon, and remove space
* after colon
*/
if (a_types[ix].have_colon) {
ADV_SPACE(after);
if (*after != ':') {
errret = ESDP_ATTRIBUTES_NO_COLON;
break;
}
after++;
if (a_types[ix].remove_spaces_after_colon) {
ADV_SPACE(after);
}
}
/*
* Call the correct parsing routine
*/
errret = (a_types[ix].parse_routine)(a_types[ix].arg, after, sptr, mptr);
break;
}
ix++;
}
/*
* Worse comes to worst, store the whole line
*/
if (parsed == FALSE || errret != 0) {
if (sdp_add_string_to_list(mptr == NULL ?
&sptr->unparsed_a_lines :
&mptr->unparsed_a_lines,
line) == FALSE) {
return (ST_ERROR_NO_MEMORY);
}
}
return (0);
}
/*
* sdp_decode_parse_bandwidth()
* parses b=<modifier>:<value>
* Inputs: lptr - pointer to line, bptr - pointer to store in
* Outputs: TRUE - valid, FALSE, invalid
*/
static int sdp_decode_parse_bandwidth (char *lptr,
bandwidth_t **bptr)
{
char *cptr, *endptr;
bandwidth_t *new, *p;
bandwidth_modifier_t modifier;
uint32_t temp;
cptr = strchr(lptr, ':');
if (cptr == NULL) {
Rtsp_Printf( "No colon in bandwidth\n");
return (ESDP_BANDWIDTH);
}
*cptr++ = '\0';
if (strncmp(lptr, "as", strlen("as")) == 0) {
modifier = BANDWIDTH_MODIFIER_AS;
} else if (strncmp(lptr, "ct", strlen("ct")) == 0) {
modifier = BANDWIDTH_MODIFIER_CT;
} else {
modifier = BANDWIDTH_MODIFIER_USER;
endptr = cptr - 2;
while (isspace(*endptr) && endptr >lptr) *endptr-- = '\0';
}
if (*cptr == '\0') {
Rtsp_Printf( "No bandwidth in bandwidth\n");
return (ESDP_BANDWIDTH);
}
temp = (uint32_t)strtoul(cptr, &endptr, 10);
if (*endptr != '\0') {
if(*endptr=='.')
{
temp++;
}
else
{
Rtsp_Printf( "Error in decoding bandwidth value %s\n", cptr);
return (ESDP_BANDWIDTH);
}
}
new = Rtsp_Malloc(sizeof(bandwidth_t),__LINE__,__FILE__);
if (new == NULL) {
return (ST_ERROR_NO_MEMORY);
}
new->modifier = modifier;
if (modifier == BANDWIDTH_MODIFIER_USER) {
new->user_band = strdup(lptr);
if (new->user_band == NULL) {
Rtsp_Free(new,__LINE__,__FILE__);
return (ST_ERROR_NO_MEMORY);
}
} else {
new->user_band = NULL;
}
new->bandwidth = temp;
new->next = NULL;
if (*bptr == NULL) {
*bptr = new;
} else {
p = *bptr;
while (p->next != NULL) p = p->next;
p->next = new;
}
return (0);
}
/*
* sdp_decode_parse_connect()
* parse c=<network type> <address type> <connect address>
* Inputs: lptr, connect pointer
* Outputs - error code or 0 if parsed correctly
*/
static int sdp_decode_parse_connect (char *lptr, connect_desc_t *cptr)
{
char *sep, *beg;
cptr->ttl = 0;
cptr->num_addr = 0;
/* <network type> should be IN*/
sep = (char*)strsep(&lptr, SPACES);
if (sep == NULL ||
lptr == NULL ||
strcmp(sep, "IN") != 0) {
Rtsp_Printf( "IN statement missing from c\n");
return (ESDP_CONNECT);
}
/* <address type> - should be IPV4*/
ADV_SPACE(lptr);
sep =(char*)strsep(&lptr, SPACES);
if (sep == NULL || lptr == NULL) {
Rtsp_Printf( "No connection type in c=\n");
return (ESDP_CONNECT);
}
cptr->conn_type = strdup(sep);
/* Address - first look if we have a / - that indicates multicast, and a
ttl.*/
ADV_SPACE(lptr);
sep = strchr(lptr, '/');
if (sep == NULL) {
/* unicast address*/
cptr->conn_addr = strdup(lptr);
cptr->used = TRUE;
return (0);
}
/* Okay - multicast address. Take address up to / (get rid of trailing
spaces)*/
beg = lptr;
lptr = sep + 1;
sep--;
while (isspace(*sep) && sep > beg) sep--;
sep++;
*sep = '\0';
cptr->conn_addr = strdup(beg);
/* Now grab the ttl*/
ADV_SPACE(lptr);
sep = (char*)strsep(&lptr, " \t/");
if (!isdigit(*sep)) {
free_connect_desc(cptr);
/* Rtsp_Printf( "No multicast TTL in c=\n");
*/
return (ESDP_CONNECT);
}
sscanf(sep, "%u", &cptr->ttl);
/* And see if we have a number of ports*/
if (lptr != NULL) {
/* we have a number of ports, as well*/
ADV_SPACE(lptr);
if (!isdigit(*lptr)) {
/* Rtsp_Printf( "c=: garbage after multicast ttl %s\n", lptr);
*/
free_connect_desc(cptr);
return (ESDP_CONNECT);
}
sscanf(lptr, "%u", &cptr->num_addr);
}
cptr->used = TRUE;
return (0);
}
/*
* sdp_decode_parse_key()
*/
static int sdp_decode_parse_key (char *lptr, key_desc_t *kptr)
{
if (strncmp(lptr, "prompt", strlen("prompt")) == 0) {
/* handle prompt command*/
kptr->key_type = KEY_TYPE_PROMPT;
return (0);
}
if (strncmp(lptr, "clear", strlen("clear")) == 0) {
kptr->key_type = KEY_TYPE_CLEAR;
lptr += strlen("clear");
} else if (strncmp(lptr, "base64", strlen("base64")) == 0) {
kptr->key_type = KEY_TYPE_BASE64;
lptr += strlen("base64");
} else if (strncmp(lptr, "uri", strlen("uri")) == 0) {
kptr->key_type = KEY_TYPE_URI;
lptr += strlen("uri");
} else {
Rtsp_Printf( "key statement keyword error %s\n", lptr);
return (ESDP_KEY);
}
ADV_SPACE(lptr);
if (*lptr != ':') {
return (ESDP_KEY);
}
lptr++;
/* Because most of the types can have spaces, we take everything after
the colon here. To eliminate the whitespace, use ADV_SPACE(lptr);*/
kptr->key = strdup(lptr);
return (0);
}
/*
* sdp_decode_parse_media()
* decodes m= lines.
* m=<media> <port>[/<numport>] <proto> <fmt list>
* Inputs:
* lptr - pointer to line
* sptr - pointer to session description to modify
* Outputs:
* pointer to new media description
*/
static media_desc_t *sdp_decode_parse_media (char *lptr,
session_desc_t *sptr,
int *err)
{
char *mdesc, *proto, *sep;
media_desc_t *new, *mp;
uint32_t read, port_no;
string_list_t *q;
*err = 0;
/* m=<media> <port> <transport> <fmt list>*/
mdesc =(char*) strsep(&lptr, SPACES);
if (mdesc == NULL || lptr == NULL) {
Rtsp_Printf( "No media type\n");
*err = ESDP_MEDIA;
return (NULL);
}
/* <port>*/
ADV_SPACE(lptr);
read = 0;
if (!isdigit(*lptr)) {
Rtsp_Printf( "Illegal port number in media %s\n", lptr);
*err = ESDP_MEDIA;
return (NULL);
}
while (isdigit(*lptr)) {
read *= 10;
read += *lptr - '0';
lptr++;
}
ADV_SPACE(lptr);
/* number of ports (optional)*/
if (*lptr == '/') {
lptr++;
ADV_SPACE(lptr);
if (!isdigit(*lptr)) {
Rtsp_Printf( "Illegal port number in media %s\n", lptr);
*err = ESDP_MEDIA;
return (NULL);
}
sep = (char*)strsep(&lptr, SPACES);
if (lptr == NULL) {
Rtsp_Printf( "Missing keywords in media\n");
*err = ESDP_MEDIA;
return (NULL);
}
sscanf(sep, "%u", &port_no);
ADV_SPACE(lptr);
} else {
port_no = 0;
}
/* <transport> (protocol)*/
proto = (char*)strsep(&lptr, SPACES);
if (proto == NULL || lptr == NULL) {
Rtsp_Printf( "No transport in media\n");
*err = ESDP_MEDIA;
return (NULL);
}
ADV_SPACE(lptr);
if (!isalnum(*lptr)) {
*err = ESDP_MEDIA;
return (NULL);
}
/* malloc memory and set.*/
new = Rtsp_Malloc(sizeof(media_desc_t),__LINE__,__FILE__);
if (new == NULL) {
*err = ST_ERROR_NO_MEMORY;
return (NULL);
}
memset(new, 0, sizeof(media_desc_t));
new->media =(char*) strdup(mdesc);
new->port = (uint16_t)read;
new->proto = strdup(proto);
new->num_ports = (unsigned short)port_no;
#if 0 //wxf add it
new->control_string=Rtsp_Malloc(10,__LINE__,__FILE__);
#endif
/* parse format list - these are not necessarilly lists of numbers
so we store as strings.*/
q = NULL;
do {
sep =(char*)strsep(&lptr, SPACES);
if (sep != NULL) {
if (sdp_add_format_to_list(new, sep) == NULL) {
free_media_desc(new);
*err = ST_ERROR_NO_MEMORY;
return (NULL);
}
if (lptr != NULL) {
ADV_SPACE(lptr);
}
}
} while (sep != NULL);
new->parent = sptr;
/* Add to list of media*/
if (sptr->media == NULL) {
sptr->media = new;
} else {
mp = sptr->media;
while (mp->next != NULL) mp = mp->next;
mp->next = new;
}
return (new);
}
/*
* sdp_decode_parse_origin()
* parses o= line
* o=<username> <session id> <version> <network type> <addr type> <addr>
*
* Inputs:
* lptr - pointer to line to parse
* sptr - session desc
* Output - TRUE, valid, FALSE, invalid
*/
static int sdp_decode_parse_origin (char *lptr, session_desc_t *sptr)
{
char *username, *sep;
/* Username - leave null if "-"*/
username =(char*)strsep(&lptr, SPACES);
if (username == NULL || lptr == NULL) {
Rtsp_Printf( "o=: no username\n");
return (ESDP_ORIGIN);
}
ADV_SPACE(lptr);
if (strcmp(username, "-") != 0) {
sptr->orig_username = strdup(username);
}
if (strtou64(&lptr, &sptr->session_id) == FALSE) {
Rtsp_Printf( "Non-numeric session id\n");
return (ESDP_ORIGIN);
}
if (strtou64(&lptr, &sptr->session_version) == FALSE) {
Rtsp_Printf( "Non-numeric session version\n");
return (ESDP_ORIGIN);
}
ADV_SPACE(lptr);
sep = (char*)strsep(&lptr, SPACES);
if ((sep == NULL) ||
(lptr == NULL) ||
(strcmp(sep, "IN") != 0)) {
Rtsp_Printf( "o=: no IN statement\n");
return (ESDP_ORIGIN);
}
ADV_SPACE(lptr);
sep = (char*)strsep(&lptr, SPACES);
if (sep == NULL || lptr == NULL) {
Rtsp_Printf( "o=: No creation address type\n");
return (ESDP_ORIGIN);
}
sptr->create_addr_type = strdup(sep);
ADV_SPACE(lptr);
sep =(char*) strsep(&lptr, SPACES);
if (sep == NULL) {
Rtsp_Printf( "o=: No creation address\n");
return (ESDP_ORIGIN);
}
sptr->create_addr =(char*) strdup(sep);
return (0);
}
/*
* sdp_decode_parse_time()
* decode t= statements
*
* Inputs:
* sptr - pointer to session_desc_t to write into.
* lptr - pointer to line. Should point at first number (spaces removed)
*
* Outputs:
* pointer to session_time_desc_t to use as current one.
* NULL if string invalid
*/
static session_time_desc_t *sdp_decode_parse_time (char *lptr,
session_desc_t *sptr,
int *err)
{
session_time_desc_t *tptr;
uint32_t start, end;
*err = 0;
if (!isdigit(*lptr)) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -