`
阿尔萨斯
  • 浏览: 4398658 次
社区版块
存档分类
最新评论

RTMPDump(libRTMP)源代码分析 2:解析RTMP地址——RTMP_ParseURL()

 
阅读更多

注:此前写了一些列的分析RTMPdump(libRTMP)源代码的文章,在此列一个列表:
RTMPdump 源代码分析 1: main()函数
RTMPDump(libRTMP)源代码分析 2:解析RTMP地址——RTMP_ParseURL()
RTMPdump(libRTMP) 源代码分析 3: AMF编码
RTMPdump(libRTMP)源代码分析 4: 连接第一步——握手(Hand Shake)
RTMPdump(libRTMP) 源代码分析 5: 建立一个流媒体连接 (NetConnection部分)
RTMPdump(libRTMP) 源代码分析 6: 建立一个流媒体连接 (NetStream部分 1)
RTMPdump(libRTMP) 源代码分析 7: 建立一个流媒体连接 (NetStream部分 2)
RTMPdump(libRTMP) 源代码分析 8: 发送消息(Message)
RTMPdump(libRTMP) 源代码分析 9: 接收消息(Message)(接收视音频数据)
RTMPdump(libRTMP) 源代码分析 10: 处理各种消息(Message)

===============================


之前分析了一下RTMPDump的Main()函数,其中获取RTMP流媒体数据很重要的前提是RTMP的URL的解析。如果没有这一步,那程序在强大也是白搭。现在来解析一下这个函数吧:RTMP_ParseURL()。

下面首先回顾一下RTMP的URL的格式:

rtmp://localhost/vod/mp4:sample1_1500kbps.f4v

“://”之前的是使用的协议类型,可以是rtmp,rtmpt,rtmps等

之后是服务器地址

再之后是端口号(可以没有,默认1935)

在之后是application的名字,在这里是“vod”

最后是流媒体文件路径。

关于URL就不多说了,可以查看相关文档,下面贴上注释后的代码(整个parseurl.c):

/*
 * 本文件主要包含了对输入URL的解析
 */
#include "stdafx.h"
#include <stdlib.h>
#include <string.h>

#include <assert.h>
#include <ctype.h>

#include "rtmp_sys.h"
#include "log.h"

/*解析URL,得到协议名称(protocol),主机名称(host),应用程序名称(app)
 *
 */
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;

	/* 字符串解析 */
	/* 查找“://”  */
	//函数原型:char *strstr(char *str1, char *str2);
	//功能:找出str2字符串在str1字符串中第一次出现的位置(不包括str2的串结束符)。
	//返回值:返回该位置的指针,如找不到,返回空指针。
	p = strstr((char *)url, "://");
	if(!p) {
		RTMP_Log(RTMP_LOGERROR, "RTMP URL: No :// in url!");
		return FALSE;
	}
	{
	//指针相减,返回“://”之前字符串长度len
	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:
	//获取主机名称
	//跳过“://”
	p+=3;

	/* 检查一下主机名 */
	if(*p==0) {
		RTMP_Log(RTMP_LOGWARNING, "No hostname in URL!");
		return FALSE;
	}
	//原型:char *strchr(const char *s,char c); 
	//功能:查找字符串s中首次出现字符c的位置
	//说明:返回首次出现c的位置的指针,如果s中不存在c则返回NULL。 
	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;
	}

	/* 获取端口号 */
	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;

	{
	/* 获取应用程序(application)
	 *
	 * rtmp://host[:port]/app[/appinstance][/...]
	 * application = app[/appinstance]
	 */

	char *slash2, *slash3 = NULL;//指向第二个斜杠,第三个斜杠的指针
	int applen, appnamelen;

	slash2 = strchr(p, '/');//指向第二个斜杠
	if(slash2)
		slash3 = strchr(slash2+1, '/');//指向第三个斜杠,注意slash2之所以+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(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;
}

/*
 * 从URL中获取播放路径(playpath)。播放路径是URL中“rtmp://host:port/app/”后面的部分
 *
 * 获取FMS能够识别的播放路径
 * mp4 流: 前面添加 "mp4:", 删除扩展名
 * mp3 流: 前面添加 "mp3:", 删除扩展名
 * flv 流: 删除扩展名
 */
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;
}

rtmpdump源代码(Linux):http://download.csdn.net/detail/leixiaohua1020/6376561

rtmpdump源代码(VC 2005 工程):http://download.csdn.net/detail/leixiaohua1020/6563163


分享到:
评论

相关推荐

    rtmpdump2.3 librtmp 静态库、动态库、源代码

    3. 分析流数据:开发者可以利用librtmp库解析RTMP协议的数据包,获取关于流的信息,如元数据、时间戳等。 4. 自定义应用开发:librtmp的API允许开发者构建自己的应用,比如创建一个能够与RTMP服务器交互的流媒体...

    rtmpdump-2.3-android.zip_ rtmpdump andro_android_android librtmp

    在压缩包中的"rtmpdump-2.3"可能是rtmpdump的源代码或者编译好的二进制文件,用户可以进一步查看源码理解其工作原理,或者直接在Android设备上使用编译后的二进制文件进行流媒体操作。对于开发者来说,这为自定义...

    rtmpdump-2.2e.tar.gz_dump_rtmp_rtmp server_rtmpdump

    3. `src/rtmpdump.c`:rtmpdump的主要源代码文件,包含RTMP连接管理、命令处理和数据流解析等功能。 4. `src/utils.c`和其他辅助源文件:这些文件提供各种辅助功能,如命令行解析、日志记录等。 5. `include/rtmp.h`...

    rtmpdump源代码.rar

    2. **RTMP协议解析**:源代码会解析RTMP协议的固定头部、命令消息和数据消息,理解不同类型的AMF(Action Message Format)编码。 3. **文件写入**:rtmpdump将接收到的数据流写入本地文件,实现流媒体的录制或保存...

    rtmpS.rar_rtmp_rtmpdump_rtmps_rtmp客户端_读取RTMP

    开发者可以利用rtmpdump来分析RTMP流量,或者在没有原始流源的情况下记录和播放RTMP内容。此外,rtmpdump也可以用来下载RTMP流,例如从直播网站获取视频内容。 4. RTMP客户端:是指能够连接到RTMP服务器并接收流...

    rtmpdump-2.4.zip_rtmpdump_rtmpdump 2.4

    源代码可以让你深入理解RTMP协议的工作原理,以及rtmpdump如何实现数据的捕获和处理。这对于想要自定义或扩展rtmpdump功能的人来说尤其重要。 rtmpdump.exe是rtmpdump的可执行文件,你可以用它来从RTMP服务器上下载...

    rtmpdump.zip_C++_rtmp_rtmpdump

    1. 源代码文件:包含了实现RTMP协议解析和操作的C++源代码。 2. 头文件:定义了类、函数和常量等接口,供其他源文件引用。 3. 编译脚本或配置文件:用于设置编译选项和链接库,确保在VS2005环境下成功编译。 4. ...

    rtmpdump-v1.6.tar.gz_rtmp_rtmpdump

    《rtmpdump:深入解析RTMP流媒体抓取工具》 RTMP(Real Time Messaging Protocol)是Adobe Systems开发的一种协议,主要用于在互联网上传输实时音视频数据,广泛应用于在线直播、视频会议等领域。rtmpdump是一款...

    rtmpdump for vs2008

    - 添加源文件:将rtmpdump和librtmp的源代码添加到项目中。 - 适应平台:修改源代码中的编译器特定宏和包含路径,以适应VS2008环境。 - 链接库设置:确保正确配置了所有依赖库,如zlib等。 - 编译和调试:编译...

    rtmpdump 编译成功 所有支持的库

    在编译rtmpdump时,需要将librtmp_src文件夹中的源代码与其他依赖库合并,并配置合适的编译选项。对于Windows环境,这通常涉及设置项目属性、链接库路径和包含目录。完成编译后,将生成rtmpdump可执行文件,可用于与...

    rtmpdump-2.4资源

    rtmpdump能够解析并操作RTMP流,允许用户下载、回放或分析RTMP内容。 ### rtmpdump-2.4特点 1. **跨平台**: rtmpdump-2.4不仅支持常见的Linux发行版,还特别适应树莓派这样的小型计算设备,基于Debian的jessie系统...

    rtmpdump.rar_it_rtmpdump

    《rtmpdump:深入解析RTMP协议与C语言实现》 RTMP(Real Time Messaging Protocol)是Adobe Systems公司开发的一种实时传输协议,主要用于在互联网上传输音视频数据。rtmpdump是一个开源工具,用于交互式地捕获、...

    rtmpdump.rar_rtmpdump

    同时,开发者也可以利用rtmpdump的源代码,学习如何实现RTMP协议的相关功能,为自己的项目提供支持。 然而,随着HLS (HTTP Live Streaming) 和DASH (Dynamic Adaptive Streaming over HTTP) 等适应性更强的流媒体...

    rtmpdump-2.2c.tar.gz_RTMP源码_rtmpdump

    rtmpdump-2.2c源码包中包含的主要文件可能有头文件、源代码文件、Makefile以及其他编译所需的配置文件。开发者需要具备C语言基础,对网络编程和编译流程有一定的了解,才能成功编译这个项目。以下是对rtmpdump源码的...

    rtmpdump-2.2b.tar.gz_RTMP协议详解_rtmp_rtmp c#_rtmpdump_rtmp下载

    rtmp协议解析,下载。用于rtmp类型的视频下载

    rtmpdump-2.3.rar_rtmpdump-2.3_arm64

    2. **数据块处理**:在连接建立并创建流后,rtmpdump会解析和处理数据块,这些数据块通常包含音频、视频帧或其他类型的数据,它们被封装在FLV(Flash Video)格式中。 3. **命令消息解析**:rtmpdump不仅要处理数据...

    RTMP.zip_6NM_rtmp_rtmp 客户端_rtmp 解析_rtmp解析

    这个"RTMP.zip_6NM_rtmp_rtmp 客户端_rtmp 解析_rtmp解析"的压缩包文件很可能包含了一个关于RTMP客户端的实现,特别是针对AMF(Action Message Format)数据的解析。 RTMP协议通常用于流媒体服务器如Adobe Flash ...

    rtmpdump 真实的

    "bin"目录通常存放可执行文件,而"librtmp_src"则表示RTMP库的源代码,这是rtmpdump的核心部分,用于处理与RTMP服务器的通信。 编译rtmpdump时,你需要确保你有正确的开发环境,例如Visual Studio 2010,因为它是一...

    rtmpdump.zip

    2. **解压文件**:将“rtmpdump.zip”解压缩到一个工作目录,通常会有一个名为“rtmpdump”的主文件夹,里面包含源代码和头文件。 3. **创建项目**:在Visual Studio中创建一个新的Win32控制台应用程序项目,选择...

    rtmpdump-2.3 linrtmp 源代码 动态库

    2. **编译好的动态库**:预编译的动态库文件(如librtmp.so)使得其他应用程序可以直接链接并使用rtmpdump的功能,而无需重新编译整个源代码。这对于开发基于rtmpdump的应用程序非常方便。 使用rtmpdump-2.3,你...

Global site tag (gtag.js) - Google Analytics