RTMP学习(六)rtmpdump源码阅读(1)总体流程

rtmpdump总体流程



为了更加深入理解rtmp协议,下面分析一个开源的rtmp工具:rtmpdump。下载地址:https://github.com/aajanki/rtmpdump


rtmpdump实际就是一个下载工具,它会把URL中指定的资源下载下来

1、初始化

2、解析URL

3、打开文件(把URL资源保存到本地的文件)

4、建立连接

5、建立流

6、开始下载

7、下载完成,关闭连接,清理资源


下面是简化过的main函数,只保留核心的几个函数

int
main(int argc, char **argv)
{
	// *** 只保留核心代码

	// rtmp初始化
	RTMP_Init(&rtmp);


	// 参数解析
	while ((opt =
		getopt_long(argc, argv,
		"hVveqzr:s:t:p:a:b:f:o:u:C:n:c:l:y:Ym:k:d:A:B:T:w:x:W:X:S:#j:J:",
		longopts, NULL)) != -1)
	{
		switch (opt)
		{
		case 'h':
			usage(argv[0]);
			return RD_SUCCESS;
		case 'r':
		{
			AVal parsedHost, parsedApp, parsedPlaypath;
			unsigned int parsedPort = 0;
			int parsedProtocol = RTMP_PROTOCOL_UNDEFINED;

			// URL解析
			if (!RTMP_ParseURL
				(optarg, &parsedProtocol, &parsedHost, &parsedPort,
				&parsedPlaypath, &parsedApp))
			{
				RTMP_Log(RTMP_LOGWARNING, "Couldn't parse the specified url (%s)!",
					optarg);
			}
			else
			{
				if (!hostname.av_len)
					hostname = parsedHost;
				if (port == -1)
					port = parsedPort;
				if (playpath.av_len == 0 && parsedPlaypath.av_len)
				{
					playpath = parsedPlaypath;
				}
				if (protocol == RTMP_PROTOCOL_UNDEFINED)
					protocol = parsedProtocol;
				if (app.av_len == 0 && parsedApp.av_len)
				{
					app = parsedApp;
				}
			}
			break;
		}
		
		default:
			RTMP_LogPrintf("unknown option: %c\n", opt);
			usage(argv[0]);
			return RD_FAILED;
			break;
		}
	}


	// 启动流
	RTMP_SetupStream(&rtmp, protocol, &hostname, port, &sockshost, &playpath,
		&tcUrl, &swfUrl, &pageUrl, &app, &auth, &swfHash, swfSize,
		&flashVer, &subscribepath, &usherToken, &WeebToken, dSeek, dStopOffset, bLiveStream, timeout);

	

	if (!file)
	{
		if (bStdoutMode)
		{
			file = stdout;
			SET_BINMODE(file);
		}
		else
		{
			file = fopen(flvFile, "w+b");
			if (file == 0)
			{
				RTMP_LogPrintf("Failed to open file! %s\n", flvFile);
				return RD_FAILED;
			}
		}
	}



	while (!RTMP_ctrlC)
	{
		RTMP_Log(RTMP_LOGDEBUG, "Setting buffer time to: %dms", bufferTime);
		RTMP_SetBufferMS(&rtmp, bufferTime);

		if (first)
		{
			first = 0;
			RTMP_LogPrintf("Connecting ...\n");

			// 建立连接
			if (!RTMP_Connect(&rtmp, NULL))
			{
				nStatus = RD_NO_CONNECT;
				break;
			}

			RTMP_Log(RTMP_LOGINFO, "Connected...");

			// User defined seek offset
			if (dStartOffset > 0)
			{
				// Don't need the start offset if resuming an existing file
				if (bResume)
				{
					RTMP_Log(RTMP_LOGWARNING,
						"Can't seek a resumed stream, ignoring --start option");
					dStartOffset = 0;
				}
				else
				{
					dSeek = dStartOffset;
				}
			}

			// Calculate the length of the stream to still play
			if (dStopOffset > 0)
			{
				// Quit if start seek is past required stop offset
				if (dStopOffset <= dSeek)
				{
					RTMP_LogPrintf("Already Completed\n");
					nStatus = RD_SUCCESS;
					break;
				}
			}

			// 建立流连接
			if (!RTMP_ConnectStream(&rtmp, dSeek))
			{
				nStatus = RD_FAILED;
				break;
			}
		}
		else
		{
			nInitialFrameSize = 0;

			if (retries)
			{
				RTMP_Log(RTMP_LOGERROR, "Failed to resume the stream\n\n");
				if (!RTMP_IsTimedout(&rtmp))
					nStatus = RD_FAILED;
				else
					nStatus = RD_INCOMPLETE;
				break;
			}
			RTMP_Log(RTMP_LOGINFO, "Connection timed out, trying to resume.\n\n");
			/* Did we already try pausing, and it still didn't work? */
			if (rtmp.m_pausing == 3)
			{
				/* Only one try at reconnecting... */
				retries = 1;
				dSeek = rtmp.m_pauseStamp;
				if (dStopOffset > 0)
				{
					if (dStopOffset <= dSeek)
					{
						RTMP_LogPrintf("Already Completed\n");
						nStatus = RD_SUCCESS;
						break;
					}
				}
				if (!RTMP_ReconnectStream(&rtmp, dSeek))
				{
					RTMP_Log(RTMP_LOGERROR, "Failed to resume the stream\n\n");
					if (!RTMP_IsTimedout(&rtmp))
						nStatus = RD_FAILED;
					else
						nStatus = RD_INCOMPLETE;
					break;
				}
			}
			else if (!RTMP_ToggleStream(&rtmp))
			{
				RTMP_Log(RTMP_LOGERROR, "Failed to resume the stream\n\n");
				if (!RTMP_IsTimedout(&rtmp))
					nStatus = RD_FAILED;
				else
					nStatus = RD_INCOMPLETE;
				break;
			}
			bResume = TRUE;
		}

		// 下载
		nStatus = Download(&rtmp, file, dSeek, dStopOffset, duration, bResume,
			metaHeader, nMetaHeaderSize, initialFrame,
			initialFrameType, nInitialFrameSize,
			nSkipKeyFrames, bStdoutMode, bLiveStream, bHashes,
			bOverrideBufferTime, bufferTime, &percent);
		free(initialFrame);
		initialFrame = NULL;

		/* If we succeeded, we're done.
		 */
		if (nStatus != RD_INCOMPLETE || !RTMP_IsTimedout(&rtmp) || bLiveStream)
			break;
	}

	if (nStatus == RD_SUCCESS)
	{
		RTMP_LogPrintf("Download complete\n");
	}
	else if (nStatus == RD_INCOMPLETE)
	{
		RTMP_LogPrintf
			("Download may be incomplete (downloaded about %.2f%%), try resuming\n",
			percent);
	}

clean:

	// 关闭,清理
	RTMP_Log(RTMP_LOGDEBUG, "Closing connection.\n");
	RTMP_Close(&rtmp);

	if (file != 0)
		fclose(file);

	CleanupSockets();

#ifdef _DEBUG
	if (netstackdump != 0)
		fclose(netstackdump);
	if (netstackdump_read != 0)
		fclose(netstackdump_read);
#endif
	return nStatus;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值