网络直播电视之寻找直播地址(下)

接上文,上文中提到获取网络直播电视地址的方法,但是大量信息需要人工的方式进行处理,过于麻烦。所以本文针对三级的XML解析和下载工作进行处理。

技术点:1、利用tinyXML完成XML的解析工作 tinyxml下载

2、利用libcurl完成xml的下载工作 libcurl下载

公用下载函数:

// 下载相关的XML
static size_t write_data(void *buffer, size_t size, size_t nmemb, void *userp)
{
	size_t nsize=size*nmemb;

	//…在这里保存数据
	string *strHtml=(string*)userp;
	strHtml->append((char*)buffer,nsize);

	return nsize;
}
bool downloadXml(const char* fileUrl, string& xmlStr)
{
	if ("" == fileUrl)
	{
		dxreport("downloadXml: fileUrl is empty ...");
		return false;
	}

	xmlStr = "";			// 清空缓存XML
	CURL* m_curl = curl_easy_init();
	if (NULL == m_curl)
	{
		dxreport("downloadXml: create curl fail ...");
		return false;
	}

	string* str = new string(); 
	curl_easy_reset(m_curl);                                                     //主要是在重复调用GET/POST时,清空curl中的设置
	curl_easy_setopt(m_curl, CURLOPT_URL, fileUrl);
	curl_easy_setopt(m_curl, CURLOPT_FOLLOWLOCATION, 1);
	curl_easy_setopt(m_curl, CURLOPT_WRITEDATA,(void *)str); 
	curl_easy_setopt(m_curl, CURLOPT_WRITEFUNCTION, write_data);
	
	CURLcode res = curl_easy_perform(m_curl);  
	curl_easy_cleanup(m_curl); 

	if (res != CURLE_OK || str->length() == 0)
	{
		dxreport("downloadXml: download xml fail! url = %s", fileUrl);
		cout << fileUrl << endl;
		return false;
	}

	xmlStr = *str;
	return true;
}


解析第一级XML:

<?xml version="1.0" encoding="UTF-8"?>
<atv>
	<body>
		<listScrollerSplit id="com.sample.list-scroller-split">
			<header>
				<simpleHeader>
					<title>电视直播</title>
				</simpleHeader>
			</header>
			<menu>
				<sections>
					<menuSection>
						<header>
							<textDivider alignment="left">
								<title>类别选择</title>
							</textDivider>
						</header>
						<items>
							<oneLineMenuItem id="list_1">
								<label>央视直播</label>
								<preview>
									<link>http://atv.jianguoke.com/appletv/tv/list_1.xml</link>
								</preview>
							</oneLineMenuItem>
						</items>
					</menuSection>
				</sections>
			</menu>
		</listScrollerSplit>
	</body>
</atv>

样例XML如上所示,现在我们开始解析工作。


// 解析第一级XML
bool parseFristXml(const char* fileName, list<CHANNEL_INFO>& listChannel)
{
	string strXml = "";
	if (false == downloadXml(fileName, strXml))
	{
		return false;
	}

	TiXmlDocument* document = new TiXmlDocument();
	if (false == document->Parse(strXml.c_str()))
	{
		return false;
	}

	/*TiXmlDeclaration *decl;
        decl = document->FirstChild()->ToDeclaration();*/
	// 查找到根部
	TiXmlElement* rootElement = document->RootElement();

	TiXmlElement* keyBody = rootElement->FirstChildElement();
	TiXmlElement* keyListScrollerSplit = keyBody->FirstChildElement();

	TiXmlElement* keyHeadFrist = keyListScrollerSplit->FirstChildElement();
	TiXmlElement* keyMenu = keyHeadFrist->NextSiblingElement();
	if (keyMenu == NULL)
	{
		return false;
	}

	// 进入到menu中
	TiXmlElement* keySections = keyMenu->FirstChildElement();
	TiXmlElement* keySectionsMenu = keySections->FirstChildElement();
	TiXmlElement* keySectionsHeaderMenu = keySectionsMenu->FirstChildElement();
	TiXmlElement* keySectionsItems = keySectionsHeaderMenu->NextSiblingElement(); // 发现解析头部
	TiXmlElement* item = keySectionsItems->FirstChildElement();					  // 取得第一个标签
	while (item)
	{
		CHANNEL_INFO info;
		TiXmlElement* oneLineMenuItem = item->FirstChildElement(); // 获取lable的内容
		info.name = changeTxtEncoding(oneLineMenuItem->GetText());
		oneLineMenuItem = oneLineMenuItem->NextSiblingElement()->FirstChildElement();
		info.fileUrl = oneLineMenuItem->GetText();
		listChannel.push_back(info);							   // 存储数据 
		item = item->NextSiblingElement();						   // 切到下个标记
	}
	return true;
}

tinyXML函数的具体使用在这里就不累赘了,针对TinyXML解析方法可参见博客的其他相关内容。

解析第二级XML:

<?xml version="1.0" encoding="UTF-8"?>
<atv>
	<head>
		<script src="http://atv.jianguoke.com/appletv/video.js"/>
	</head>
	<body>
		<preview>
			<scrollerPreview id="com.sample.scrollerPreview">
				<items>
					<grid id="grid_1" columnCount="5">
						<items>
							<sixteenByNinePoster id="type1_1" alwaysShowTitles="true" accessibilityLabel="" onHoldSelect="savevideofav('http://atv.jianguoke.com/appletv/tv/live_1_1.xml', 'http://atv.jianguoke.com/appletv/tv/img/m_cctv1.png', 'CCTV-1 综合', '5')" onSelect="playvideo('http://atv.jianguoke.com/appletv/tv/live_1_1.xml', 'http://atv.jianguoke.com/appletv/tv/live_1_1.xml', 'CCTV-1 综合', '5')" onPlay="playvideo('http://atv.jianguoke.com/appletv/tv/live_1_1.xml', 'http://atv.jianguoke.com/appletv/tv/live_1_1.xml', 'CCTV-1 综合', '5')">
								<title>CCTV-1 综合</title>
								<image>http://atv.jianguoke.com/appletv/tv/img/m_cctv1.png</image>
								<defaultImage>resource://Poster.png</defaultImage>
							</sixteenByNinePoster>
							<sixteenByNinePoster id="type1_2" alwaysShowTitles="true" accessibilityLabel="" onHoldSelect="savevideofav('http://atv.jianguoke.com/appletv/tv/live_1_2.xml', 'http://atv.jianguoke.com/appletv/tv/img/m_cctv2.png', 'CCTV-2 财经', '5')" onSelect="playvideo('http://atv.jianguoke.com/appletv/tv/live_1_2.xml', 'http://atv.jianguoke.com/appletv/tv/live_1_2.xml', 'CCTV-2 财经', '5')" onPlay="playvideo('http://atv.jianguoke.com/appletv/tv/live_1_2.xml', 'http://atv.jianguoke.com/appletv/tv/live_1_2.xml', 'CCTV-2 财经', '5')">
								<title>CCTV-2 财经</title>
								<image>http://atv.jianguoke.com/appletv/tv/img/m_cctv2.png</image>
								<defaultImage>resource://Poster.png</defaultImage>
							</sixteenByNinePoster>
						</items>
					</grid>
				</items>
			</scrollerPreview>
		</preview>
	</body>
</atv>

处理函数为:


// 解析第二级XML
bool parseSecondXml(list<CHANNEL_INFO> fristXmlChannel, list<CHANNEL_INFO>& secondXmlChannel)
{
	int len = fristXmlChannel.size();
	if (len == 0)
	{
		dxreport("parseSecondXml: get fristXmlChannel is empty!");
		return false;
	}

	for (int i = 0; i < len; i++)
	{
		CHANNEL_INFO info;
		list<CHANNEL_INFO>::iterator iter = fristXmlChannel.begin();
		info = (*iter);
		fristXmlChannel.pop_front();	// 清除头部的数据

		string strXml = "";
		if (false == downloadXml(info.fileUrl.c_str(), strXml))
		{
			continue;
		}

		// 进行二级解析XML
		TiXmlDocument* document = new TiXmlDocument();
		if (false == document->Parse(strXml.c_str()))
		{
			return false;
		}

		TiXmlElement* element = document->RootElement();
		element = element->FirstChildElement();
		element = element->NextSiblingElement(); // body
		for (int i = 0; i < 6; i++)
		{
			element = element->FirstChildElement();
		}

		// 获取三级XML下载地址 
		while (element)
		{
			TiXmlAttribute* attribute = element->FirstAttribute();
			while (attribute)
			{
				string keyName = attribute->Name();
				if (keyName == "onPlay")
				{
					// 获取到的内容如下格式:
					//"playvideo('http://atv.jianguoke.com/appletv/tv/live_1_1.xml', 'http://atv.jianguoke.com/appletv/tv/live_1_1.xml', 'CCTV-1 综合', '5')"
					string strContent = attribute->Value();
					
					// 解析字符串
					int len = strContent.length();
					string keyStr[4] = {"", "", "", ""};
					string str = "";
					int keyNum = 0;
					for (int i = 0; i < len; i ++)
					{
						if (strContent[i] == '\'')
						{
							if (strContent[i+1] == ',')
							{
								keyStr[keyNum] = str;
								keyNum ++;
							}
							str = "";
							continue;
						}
						str += strContent[i];
					}
					
					// 存储数据
					CHANNEL_INFO newInfo;
					newInfo.fileUrl = keyStr[0];
					newInfo.name	= changeTxtEncoding(keyStr[2].c_str());
					secondXmlChannel.push_back(newInfo);
				}
				attribute = attribute->Next();
			}
			
			element = element->NextSiblingElement();
		}
		

	}
	
	return true;
}

解析第三级XML:

<?xml version="1.0" encoding="UTF-8"?>
<atv>
	<body>
		<videoPlayer id="com.sample.video-player">
			<httpFileVideoAsset id="live_3_5">
				<mediaURL>http://182.140.144.32:8080/playlist/37.m3u8?key=rkH0PG-pfffEkcMUDSZoEwbswucCuObIj1fYeg..</mediaURL>
				<title/>
				<description/>
				<image/>
			</httpFileVideoAsset>
		</videoPlayer>
	</body>
</atv>

解析函数:


// 解析最后一级XML
bool parseEndXml(list<CHANNEL_INFO> secondXmlChannel, list<CHANNEL_INFO>& endXmlChannel)
{
	int len = secondXmlChannel.size();
	if (len == 0)
	{
		dxreport("parseSecondXml: get fristXmlChannel is empty!");
		return false;
	}

	for (int i = 0; i < len; i++)
	{
		CHANNEL_INFO info;
		list<CHANNEL_INFO>::iterator iter = secondXmlChannel.begin();
		info = (*iter);
		secondXmlChannel.pop_front();	// 清除头部的数据

		string strXml = "";
		if (false == downloadXml(info.fileUrl.c_str(), strXml))
		{
			continue;
		}

		// 进行三级级解析XML
		TiXmlDocument* document = new TiXmlDocument();
		if (false == document->Parse(strXml.c_str()))
		{
			return false;
		}

		TiXmlElement* element = document->RootElement();
		for (int i = 0; i < 4; i++)
		{
			element = element->FirstChildElement();
		}
		CHANNEL_INFO newInfo;
		newInfo.fileUrl = element->GetText();
		newInfo.name	= info.name;
		endXmlChannel.push_back(newInfo);

		cout << newInfo.name << ":" << newInfo.fileUrl << endl;
	}
	return true;
}


以上就是相关处理内容。望给各位有所帮助 ....



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值