⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 layer1.cpp

📁 mysee网络直播源代码Mysee Lite是Mysee独立研发的网络视频流媒体播放系统。在应有了P2P技术和一系列先进流媒体技术之后
💻 CPP
字号:
/*
 *  Openmysee
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program 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 General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 */
#include "stdafx.h"
#include "Communicator.h"
#include "Layer1.h"
#include "Http_Fetcher.h"

// 在所有服务器都已经支持切换编码之前,需要从GTV文件中读取媒体类型数据
//#define READ_GTV_MEDIA

namespace NPLayer1 {
Layer1::Layer1() {
	comm = NULL;
}

Layer1::~Layer1() {
	delete comm;
}

P2P_RETURN_TYPE Layer1::Request(
								LPCSTR url, 			// in, 要播放的gtv地址或者路径
								const HWND notifyWnd, 	// in, layer1发送消息的窗口
								const UINT notifyCode,	// in, layer1发送消息的msg ID
								const UINT16	channelID	//in, layer1发送消息的目标channel ID, , 将附加到WPARAM里面的HIWORD,
								)
{
	if(comm)
		return PRT_DUP_INIT;
	if(!url || strlen(url) >= MAX_PATH_EX)
		return PRT_BAD_URL;

	string resname;
	string hashcode;
	string spList;
	string trackerList;
	UINT blockSize = BLOCK_SIZE;
	float bitRate = 40.0f;

	char szFinal[MAX_PATH_EX];
    strcpy(szFinal, url);

#ifdef READ_GTV_MEDIA
    UINT attachDataSize = 0;
    char* attachData = NULL;
#endif

	// gaov协议格式:gaov://tsip:tsport/spip:spport/res md5/res name(optional)/bitrate(optional)/
	if(strnicmp(szFinal, "gaov://", 7) == 0) {
		string temp = szFinal;
		temp.erase(0, 7);
		size_t index = temp.find('/');
		trackerList = temp.substr(0, index);
		if(index == -1)
			return PRT_BAD_URL;
		temp.erase(0, index+1);
		index = temp.find('/');
		spList = temp.substr(0, index);
		if(index == -1)
			return PRT_BAD_URL;
		temp.erase(0, index+1);
		index = temp.find('/');
		hashcode = temp.substr(0, index);
		if(index != -1) {
			temp.erase(0, index+1);
			index= temp.find('/');
			resname = temp.substr(0, index);
			if(index != -1) {
				temp.erase(0, index +1);
				index = temp.find('/');
				bitRate = static_cast<float>(atof(temp.substr(0, index).data()));
				if(index != -1) {
					temp.erase(0, index+1);
				}
			}
		}

		// 如果协议中没有包含资源名,则显示hashcoder,因为后面会检查resname是否为空 -_-
		if(resname.empty())
			resname = hashcode;
	}
	else {
		// 1. 判断是否GTV文件
		char* index = strrchr(szFinal, '.');
		if(index != NULL) {
			index++;
			if(strnicmp(index, "gtv", 3) != 0)
				return PRT_BAD_URL;
		}
		else
			return PRT_BAD_URL;

		// 2. 下载GTV文件
		bool isHttpGTV = false;
		// 如果是"HTTP://"打头的gtv,就说明需要下载
		if(strnicmp(szFinal, "http://", 7) == 0) {
			// 通过HTTP下载的文件内容保存在这里
			char buf[MAX_PATH_EX];
			if(GetTempPath(MAX_PATH_EX, buf) == 0)
				return PRT_SYS;
			itoa(GetTickCount(), buf+strlen(buf), 10);
			strcat(buf, ".gtv");

			HANDLE localFile = CreateFile(buf, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
			if(localFile == INVALID_HANDLE_VALUE)
				return PRT_SYS;
			// HTTP下载类
			HttpFetcher fetcher;
			UINT fileSize = 0;
			UINT bytesRead = fetcher.http_fetch(szFinal, localFile, fileSize, bytesRead, 0.0f/*no limit*/);
			CloseHandle(localFile);
			if(bytesRead == UINT_MAX || bytesRead == 0)
				return PRT_BAD_URL;

			// 将szFinal设置为下载完毕的GTV文件的路径
			strcpy(szFinal, buf);
			isHttpGTV = true;
		}

		// 3. 读取GTV文件的数据
		char temp[4096];
		HANDLE hFile = CreateFile(szFinal, GENERIC_READ, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
		if(hFile == INVALID_HANDLE_VALUE)
			return PRT_SYS;
		DWORD TTT = 0;
		if(!ReadFile(hFile, temp, 4096, &TTT, NULL) || TTT == 0) {
			CloseHandle(hFile);
			return PRT_SYS;
		}
		CloseHandle(hFile);

		if(isHttpGTV)
			remove(szFinal); // 删除临时gtv文件

		// 4. 解析数据
		istrstream* is = NULL;
		is = new istrstream(temp);
		if(is->fail())
			return PRT_SYS;

		string line;
		string name;
		string value;
		string inSection;
		size_t posEqual;
		while (getline(*is,line)) {
			if ( !line.length()) continue;
			if ( line[0] == '#') continue; // 注释行
			if ( line[0] == ';') continue; // 注释行

			if ( line[0] == '[') {
				inSection=line.substr(1,line.find(']')-1);
				continue;
			}

			posEqual=line.find('=');
			name = line.substr(0,posEqual);
			value = line.substr(posEqual+1);
			size_t index = value.find('\r');
			if(index != -1)
				value = value.substr(0, index);
			index = value.find('\n');
			if(index != -1)
				value = value.substr(0, index);

			if(name == "ChannelName")
				resname = value;
			else if(name == "ResourceHash")
				hashcode = value;
			else if(name == "TrackServer")
				trackerList = value;
			else if(name == "SuperPeer")
				spList = value;
			else if(name == "BlockSize")
				blockSize = atoi(value.data());
			else if(name == "BitRate")
				bitRate = static_cast<float>(atof(value.data()));
#ifdef READ_GTV_MEDIA
			else if(name == "DataLength") {
				attachDataSize = atoi(value.data());
				if(attachDataSize > 1024)
					break;
				attachData = new char[attachDataSize];
			}
			else if(name == "Data") {
				if(attachDataSize > 0) {
					char* index = strstr(temp, "Data=");
					memcpy(attachData, index+5, attachDataSize); 
				}
			}
#endif
		}
		delete is;
		is = NULL;
	}

	// 检查数据
	if(resname.empty() || hashcode.empty() || spList.empty() || trackerList.empty() || blockSize != BLOCK_SIZE)
		return PRT_BAD_URL;
	
	// 5. 创建实例,并初始化
	comm = new Communicator();
	if(!comm)
		return PRT_ALLOC;

	comm->noitfyWindow = notifyWnd;
	comm->notifyCode = notifyCode;
	comm->channelID = channelID;

	P2P_RETURN_TYPE ret = comm->Init(trackerList);
	if(ret < PRT_OK)
		return ret;

	// 6. 开始下载
	ret = comm->Request(resname.data(), hashcode.data(), spList.data(), bitRate);
	if(ret < PRT_OK)
		return ret;

#ifdef READ_GTV_MEDIA
	MediaInterval mi;
	mi.start = 0;
	mi.size = 1000000000;
	char* tmpPt = attachData;
 	memcpy(&mi.videoType, tmpPt, sizeof(MediaType));
	tmpPt += sizeof(MediaType);
	mi.videoData = new BYTE[mi.videoType.cbFormat];
	if(mi.videoType.cbFormat > 200)
		return PRT_BAD_MEDIAFORMAT;
	memcpy(mi.videoData, tmpPt, mi.videoType.cbFormat);
	tmpPt += mi.videoType.cbFormat;
	memcpy(&mi.audioType, tmpPt, sizeof(MediaType));
	tmpPt += sizeof(MediaType);
	mi.audioData = new BYTE[mi.audioType.cbFormat];
	if(mi.audioType.cbFormat > 200)
		return PRT_BAD_MEDIAFORMAT;
	memcpy(mi.audioData, tmpPt, mi.audioType.cbFormat);
	tmpPt += mi.audioType.cbFormat;

	delete [] attachData;

	comm->currRes->AddMediaInterval(mi);
#endif

	return PRT_OK;
}

// 停止当前下载
void Layer1::Stop() {
	if(!comm)
		return;

	comm->logFile.StatusOut("Incoming stop...");
	comm->StopCurrentRes();
}

// 缓冲完成
void Layer1::BufferFinished() {
	if(!comm || !comm->currRes)
		return;
	comm->currRes->EnlargeBuffer();
}

// 获取当前资源的传输信息
void Layer1::GetTransferInfo(
							 TransferInfo& ti	// out, 传输信息
							 )
{
	if(!comm)
		return;
	comm->p2pMgr.GetTransferInfo(ti);
}

// 获取当前资源Hash
BOOL Layer1::GetResourceHash(
							 LPTSTR buf, 		// out, 存储Hash的缓冲区
							 UINT& len			// in/out, 传入缓冲区的大小,返回Hash的长度
							 )
{
	if(!comm || !comm->currRes)
		return 0;
	if(!buf)
		return FALSE;
	string hashcode = comm->currRes->GetHashCode();
	if(len <= hashcode.length())
		return FALSE;
	len = hashcode.length();
	memcpy(buf, hashcode.data(), len);
	buf[len] = 0;
	return TRUE;
}

// 获取当前资源名
BOOL Layer1::GetFileName(
						 LPTSTR buf, 		// out, 存储名字的缓冲区
						 UINT& len			// in/out, 传入缓冲区的大小,返回名字的长度
						 )
{
	if(!comm || !comm->currRes)
		return 0;
	if(!buf)
		return FALSE;
	/// 三种不同版本的客户端,能够拿到不同的信息,所以要分别处理
	string resname = comm->currRes->GetResName();
	string programname = comm->currRes->GetProgramName();
	string channelname = comm->currRes->GetChannelName();
	UINT32 progtime = comm->currRes->GetProgramTimeInSeconds();
	if(programname.empty()) {
		if(len <= resname.length())
			return FALSE;
		len = resname.length();
		sprintf(buf, "%s", resname.data());
		return true;
	}
	if(channelname.empty()) {
		if(len <= resname.length()+programname.length()+64)
			return FALSE;
		len = resname.length()+programname.length()+64;
		LONGLONG curTime = comm->currRes->GetOriginTime()/10000000;
		sprintf(buf, "%s -> %s %.2d:%.2d:%.2d", resname.data(), programname.data(), 
			(int)curTime/3600, (int)curTime%3600/60, (int)curTime%60);
		return TRUE;
	}
	if(len <= channelname.length()+programname.length()+channelname.length()+64)
		return FALSE;
	len = channelname.length()+programname.length()+channelname.length()+64;
	LONGLONG curTime = comm->currRes->GetOriginTime()/10000000;
	sprintf(buf, "%s -> %s %.2d:%.2d:%.2d", channelname.data(), programname.data(), 
		(int)curTime/3600, (int)curTime%3600/60, (int)curTime%60);
	if(progtime)
		sprintf(buf+strlen(buf), "/%.2d:%.2d:%.2d", (int)progtime/3600, (int)progtime%3600/60, (int)progtime%60);
	return TRUE;
}

// 获取当前资源的缓冲百分比
int Layer1::GetBufferPercent() {
	if(!comm || !comm->currRes)
		return -1;
	return comm->currRes->GetBufferPercent();
}

// 获取当前频道的码率
float Layer1::GetChannelBitRate() {
	if(!comm || !comm->currRes)
		return 0.0f;
	return comm->currRes->GetBitRate();
}

// 获取Sample,可能得到普通Sample或者MediaType(参考struct SampleHeader的注释)
P2P_RETURN_TYPE Layer1::GetData(
								SampleHeader& header,	// out, 数据头
								PBYTE& pData,			// out, 存储数据的缓冲区
								const UINT maxSize,		// in, 缓冲区的长度
								const bool bAudio,		// in, 获取音频还是视频
								const bool bKeySample	// in, 是否寻找关键帧
								)
{
	if(!comm || !comm->currRes)
		return PRT_NOT_INIT;
	return comm->currRes->GetData(header, pData, maxSize, bAudio, bKeySample);
}
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -