📄 layer1.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 + -