123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289 |
- /*
- * 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 <stdlib.h>
- #include <string.h>
- #include <assert.h>
- #include <ctype.h>
- #include "rtmp_sys.h"
- #include "log.h"
- 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;
- 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;
- {
- /* 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;
- }
- /*
- * 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 ((*ppstart == '?') &&
- (temp=strstr(ppstart, "slist=")) != 0) {
- ppstart = temp+6;
- pplen = 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;
- }
|