obs-studio/plugins/obs-outputs/librtmp/parseurl.c

280 lines
6.7 KiB
C

/*
* Copyright (C) 2009 Andrej Stepanchuk
* Copyright (C) 2009-2010 Howard Chu
*
* This file is part of librtmp.
*
* librtmp is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1,
* or (at your option) any later version.
*
* librtmp is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with librtmp see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
* http://www.gnu.org/copyleft/lgpl.html
*/
#include "rtmp_sys.h"
#include "log.h"
int RTMP_ParseURL(const char *url, int *protocol, AVal *host, unsigned int *port,
AVal *app)
{
char *p, *end, *col, /* *ques, */ *slash, *v6;
RTMP_Log(RTMP_LOGDEBUG, "Parsing...");
*protocol = RTMP_PROTOCOL_RTMP;
*port = 0;
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);
v6 = strchr(p, ']');
// ques = strchr(p, '?');
slash = strchr(p, '/');
col = strchr((v6 && v6 < slash) ? v6 : 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;
//just.. whatever.
app->av_val = p;
app->av_len = (int)strlen(p);
if(app->av_len && p[app->av_len-1] == '/')
app->av_len--;
RTMP_Log(RTMP_LOGDEBUG, "Parsed app : %.*s", app->av_len, p);
p += app->av_len;
if (*p == '/')
p++;
return TRUE;
}
/*
* Extracts playpath from RTMP URL. playpath is the file part of the
* URL, i.e. the part that comes after rtmp://host:port/app/
*
* Returns the stream name in a format understood by FMS. The name is
* the playpath part of the URL with formatting depending on the stream
* type:
*
* mp4 streams: prepend "mp4:", remove extension
* mp3 streams: prepend "mp3:", remove extension
* flv streams: remove extension
*/
void RTMP_ParsePlaypath(AVal *in, AVal *out)
{
int addMP4 = 0;
int addMP3 = 0;
int subExt = 0;
const char *playpath = in->av_val;
const char *temp, *q, *ext = NULL;
const char *ppstart = playpath;
char *streamname, *destptr, *p;
int pplen = in->av_len;
out->av_val = NULL;
out->av_len = 0;
if (!playpath)
return;
if ((*ppstart == '?') &&
(temp=strstr(ppstart, "slist=")) != 0)
{
ppstart = temp+6;
pplen = (int)strlen(ppstart);
temp = strchr(ppstart, '&');
if (temp)
{
pplen = temp-ppstart;
}
}
q = strchr(ppstart, '?');
if (pplen >= 4)
{
if (q)
ext = q-4;
else
ext = &ppstart[pplen-4];
if ((strncmp(ext, ".f4v", 4) == 0) ||
(strncmp(ext, ".mp4", 4) == 0))
{
addMP4 = 1;
subExt = 1;
/* Only remove .flv from rtmp URL, not slist params */
}
else if ((ppstart == playpath) &&
(strncmp(ext, ".flv", 4) == 0))
{
subExt = 1;
}
else if (strncmp(ext, ".mp3", 4) == 0)
{
addMP3 = 1;
subExt = 1;
}
}
streamname = (char *)malloc((pplen+4+1)*sizeof(char));
if (!streamname)
return;
destptr = streamname;
if (addMP4)
{
if (strncmp(ppstart, "mp4:", 4))
{
strcpy(destptr, "mp4:");
destptr += 4;
}
else
{
subExt = 0;
}
}
else if (addMP3)
{
if (strncmp(ppstart, "mp3:", 4))
{
strcpy(destptr, "mp3:");
destptr += 4;
}
else
{
subExt = 0;
}
}
for (p=(char *)ppstart; pplen >0;)
{
/* skip extension */
if (subExt && p == ext)
{
p += 4;
pplen -= 4;
continue;
}
if (*p == '%')
{
unsigned int c;
sscanf(p+1, "%02x", &c);
*destptr++ = c;
pplen -= 3;
p += 3;
}
else
{
*destptr++ = *p++;
pplen--;
}
}
*destptr = '\0';
out->av_val = streamname;
out->av_len = destptr - streamname;
}