【流媒体】RTMPDump—Download(接收流媒体信息)

目录

RTMP协议相关:
【流媒体】RTMP协议概述
【流媒体】RTMP协议的数据格式
【流媒体】RTMP协议的消息类型
【流媒体】RTMPDump---主流程简单分析
【流媒体】RTMPDump---RTMP_Connect函数(握手、网络连接)
【流媒体】RTMPDump---RTMP_ConnectStream(创建流连接)

参考雷博的系列文章(可以从一篇链接到其他文章):
RTMPdump 源代码分析 1: main()函数

在进行流连接之后,还可以进行传输过来数据的下载,执行这一功能的函数是Download(),其中使用RTMP_Read()读取数据,随后使用fwrite写入文件。写入文件通常是FLV格式,如果没有指定这个file,则会默认写到stdout

c 复制代码
int
Download(RTMP * rtmp,		// connected RTMP object
	FILE * file, uint32_t dSeek, uint32_t dStopOffset, double duration, int bResume, char* metaHeader, uint32_t nMetaHeaderSize, char* initialFrame, int initialFrameType, uint32_t nInitialFrameSize, int nSkipKeyFrames, int bStdoutMode, int bLiveStream, int bRealtimeStream, int bHashes, int bOverrideBufferTime, uint32_t bufferTime, double* percent)	// percentage downloaded [out]
{
	int32_t now, lastUpdate;
	int bufferSize = 64 * 1024;
	char* buffer;
	int nRead = 0;
	off_t size = ftello(file);
	unsigned long lastPercent = 0;

	rtmp->m_read.timestamp = dSeek;

	*percent = 0.0;

	if (rtmp->m_read.timestamp)
	{
		RTMP_Log(RTMP_LOGDEBUG, "Continuing at TS: %d ms\n", rtmp->m_read.timestamp);
	}

	if (bLiveStream)
	{
		RTMP_LogPrintf("Starting Live Stream\n");
	}
	else
	{
		// print initial status
		// Workaround to exit with 0 if the file is fully (> 99.9%) downloaded
		if (duration > 0)
		{
			if ((double)rtmp->m_read.timestamp >= (double)duration * 999.0)
			{
				RTMP_LogPrintf("Already Completed at: %.3f sec Duration=%.3f sec\n",
					(double)rtmp->m_read.timestamp / 1000.0,
					(double)duration / 1000.0);
				return RD_SUCCESS;
			}
			else
			{
				*percent = ((double)rtmp->m_read.timestamp) / (duration * 1000.0) * 100.0;
				*percent = ((double)(int)(*percent * 10.0)) / 10.0;
				RTMP_LogPrintf("%s download at: %.3f kB / %.3f sec (%.1f%%)\n",
					bResume ? "Resuming" : "Starting",
					(double)size / 1024.0, (double)rtmp->m_read.timestamp / 1000.0,
					*percent);
			}
		}
		else
		{
			RTMP_LogPrintf("%s download at: %.3f kB\n",
				bResume ? "Resuming" : "Starting",
				(double)size / 1024.0);
		}
		if (bRealtimeStream)
			RTMP_LogPrintf("  in approximately realtime (disabled BUFX speedup hack)\n");
	}

	if (dStopOffset > 0)
		RTMP_LogPrintf("For duration: %.3f sec\n", (double)(dStopOffset - dSeek) / 1000.0);

	if (bResume && nInitialFrameSize > 0)
		rtmp->m_read.flags |= RTMP_READ_RESUME;
	rtmp->m_read.initialFrameType = initialFrameType;
	rtmp->m_read.nResumeTS = dSeek;
	rtmp->m_read.metaHeader = metaHeader;
	rtmp->m_read.initialFrame = initialFrame;
	rtmp->m_read.nMetaHeaderSize = nMetaHeaderSize;
	rtmp->m_read.nInitialFrameSize = nInitialFrameSize;

	buffer = (char*)malloc(bufferSize);

	now = RTMP_GetTime();
	lastUpdate = now - 1000;
	do
	{
		// 读取信息
		nRead = RTMP_Read(rtmp, buffer, bufferSize);
		//RTMP_LogPrintf("nRead: %d\n", nRead);
		if (nRead > 0)
		{
			// 将数据写入到file当中,FLV格式
			// 如果这个file没有指定,默认是stdout
			if (fwrite(buffer, sizeof(unsigned char), nRead, file) !=
				(size_t)nRead)
			{
				RTMP_Log(RTMP_LOGERROR, "%s: Failed writing, exiting!", __FUNCTION__);
				free(buffer);
				return RD_FAILED;
			}
			size += nRead;

			//RTMP_LogPrintf("write %dbytes (%.1f kB)\n", nRead, nRead/1024.0);
			if (duration <= 0)	// if duration unknown try to get it from the stream (onMetaData)
				duration = RTMP_GetDuration(rtmp);

			if (duration > 0)
			{
				// make sure we claim to have enough buffer time!
				if (!bOverrideBufferTime && bufferTime < (duration * 1000.0))
				{
					bufferTime = (uint32_t)(duration * 1000.0) + 5000;	// extra 5sec to make sure we've got enough

					RTMP_Log(RTMP_LOGDEBUG,
						"Detected that buffer time is less than duration, resetting to: %dms",
						bufferTime);
					RTMP_SetBufferMS(rtmp, bufferTime);
					RTMP_UpdateBufferMS(rtmp);
				}
				*percent = ((double)rtmp->m_read.timestamp) / (duration * 1000.0) * 100.0;
				*percent = ((double)(int)(*percent * 10.0)) / 10.0;
				if (bHashes)
				{
					if (lastPercent + 1 <= *percent)
					{
						RTMP_LogStatus("#");
						lastPercent = (unsigned long)* percent;
					}
				}
				else
				{
					now = RTMP_GetTime();
					if (abs(now - lastUpdate) > 200)
					{
						RTMP_LogStatus("\r%.3f kB / %.2f sec (%.1f%%)",
							(double)size / 1024.0,
							(double)(rtmp->m_read.timestamp) / 1000.0, *percent);
						lastUpdate = now;
					}
				}
			}
			else
			{
				now = RTMP_GetTime();
				if (abs(now - lastUpdate) > 200)
				{
					if (bHashes)
						RTMP_LogStatus("#");
					else
						RTMP_LogStatus("\r%.3f kB / %.2f sec", (double)size / 1024.0,
						(double)(rtmp->m_read.timestamp) / 1000.0);
					lastUpdate = now;
				}
			}
		}
		else
		{
#ifdef _DEBUG
			RTMP_Log(RTMP_LOGDEBUG, "zero read!");
#endif
			if (rtmp->m_read.status == RTMP_READ_EOF)
				break;
		}

	} while (!RTMP_ctrlC && nRead > -1 && RTMP_IsConnected(rtmp) && !RTMP_IsTimedout(rtmp));
	free(buffer);
	if (nRead < 0)
		nRead = rtmp->m_read.status;

	/* Final status update */
	if (!bHashes)
	{
		if (duration > 0)
		{
			*percent = ((double)rtmp->m_read.timestamp) / (duration * 1000.0) * 100.0;
			*percent = ((double)(int)(*percent * 10.0)) / 10.0;
			RTMP_LogStatus("\r%.3f kB / %.2f sec (%.1f%%)",
				(double)size / 1024.0,
				(double)(rtmp->m_read.timestamp) / 1000.0, *percent);
		}
		else
		{
			RTMP_LogStatus("\r%.3f kB / %.2f sec", (double)size / 1024.0,
				(double)(rtmp->m_read.timestamp) / 1000.0);
		}
	}

	RTMP_Log(RTMP_LOGDEBUG, "RTMP_Read returned: %d", nRead);

	if (bResume && nRead == -2)
	{
		RTMP_LogPrintf("Couldn't resume FLV file, try --skip %d\n\n",
			nSkipKeyFrames + 1);
		return RD_FAILED;
	}

	if (nRead == -3)
		return RD_SUCCESS;

	if ((duration > 0 && *percent < 99.9) || RTMP_ctrlC || nRead < 0
		|| RTMP_IsTimedout(rtmp))
	{
		return RD_INCOMPLETE;
	}

	return RD_SUCCESS;
}
相关推荐
繁华落尽,倾城殇?10 分钟前
[C++11] : atomic,nullptr,default/delete,enum class
开发语言·c++·c++11·nullptr·atomic·enum class·default/delete
代码村新手32 分钟前
C++-二叉搜索树
开发语言·c++
青风9739 分钟前
SDDGR:基于稳定扩散的深度生成重放,用于类增量对象检测(CVPR 2024)
网络·人工智能·深度学习·神经网络·计算机视觉
智者知已应修善业1 小时前
【51单片机8位数码管动态显示日期小数点风格】2023-11-13
c++·经验分享·笔记·算法·51单片机
智者知已应修善业1 小时前
【51单片机有三个LED 分别第一个灯闪三下 再到第二个灯又闪三下 再到第三个灯又闪三下 就这样循环程序】2023-11-16
c++·经验分享·笔记·算法·51单片机
byte轻骑兵3 小时前
【HID】规范精讲[20]: 蓝牙HID低功耗黑科技——Sniff Subrating如何让设备续航翻倍?
网络·科技·人机交互·hid·蓝牙键盘
liana87444 小时前
私有化视频会议:把会议室“搬”进自己的网络
网络
Cat_Rocky4 小时前
Linux-ansible之Playbook简单应用
linux·网络·ansible
汤愈韬4 小时前
IPSec工作原理——TK
网络·网络协议·网络安全·security
ElevenS_it1884 小时前
连锁门店IT运维监控实战:200+门店网络设备+POS统一纳管+按区域分组告警路由完整配置(Zabbix Proxy架构)
运维·网络·架构·zabbix