LiveResource.cpp
上传用户:liguizhu
上传日期:2015-11-01
资源大小:2422k
文件大小:25k
源码类别:

P2P编程

开发平台:

Visual C++

  1. /*
  2.  *  Openmysee
  3.  *
  4.  *  This program is free software; you can redistribute it and/or modify
  5.  *  it under the terms of the GNU General Public License as published by
  6.  *  the Free Software Foundation; either version 2 of the License, or
  7.  *  (at your option) any later version.
  8.  *
  9.  *  This program is distributed in the hope that it will be useful,
  10.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.  *  GNU General Public License for more details.
  13.  *
  14.  *  You should have received a copy of the GNU General Public License
  15.  *  along with this program; if not, write to the Free Software
  16.  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  17.  *
  18.  */
  19. #include "stdafx.h"
  20. #include ".liveresource.h"
  21. #include "Communicator.h"
  22. #include "BufferMgr.h"
  23. namespace NPLayer1 {
  24. LiveResource::LiveResource(Communicator*c ) : 
  25. BaseResource(c), A_currBlock(NULL), V_currBlock(NULL), tmpBlockData(NULL)
  26. {
  27. }
  28. LiveResource::~LiveResource(void) {
  29. Uninit(false);
  30. }
  31. // 第一次开始下载的初始化
  32. P2P_RETURN_TYPE LiveResource::Init(
  33. string resname, // 资源名
  34. string hashcode, // 资源的Hash码
  35. string strSPList, // SuperPeer列表的IP地址
  36. float bitRate) // 频道的码率
  37. {
  38. CriticalSection::Owner lock(dataLocker);
  39. try {
  40. // 不能重复初始化
  41. if(bInited)
  42. throw PRT_DUP_INIT;
  43. this->resname = resname;
  44. this->hashcode = hashcode;
  45. bufferMgr = &comm->g_bufferMgr;
  46. // 直播资源未知大小,需要的磁盘空间是小于缓冲文件大小的某个固定值
  47. // DEFAULT_SPACE必须保证整除BLOCK_SIZE
  48. blockMapSize = DEFAULT_SPACE/BLOCK_SIZE;
  49. // 初始化数组
  50. blockMapArray = new UINT[blockMapSize];
  51. blockIDArray = new UINT[blockMapSize];
  52. if(!blockMapArray || !blockIDArray)
  53. throw PRT_ALLOC;
  54. // 初始化数组所有成员为UINT_MAX
  55. fill(blockMapArray, blockMapArray+blockMapSize, UINT_MAX);
  56. fill(blockIDArray, blockIDArray+blockMapSize, UINT_MAX);
  57. P2P_RETURN_TYPE ret = ParseSPList(strSPList);
  58. if(ret != PRT_OK)
  59. throw ret;
  60. ret = InitBroadcastMember(bitRate);
  61. if(ret < PRT_OK)
  62. throw ret;
  63. }
  64. catch (P2P_RETURN_TYPE ret) {
  65. comm->logFile.StatusOut("Init Res Error!");
  66. Uninit(true);
  67. return ret;
  68. }
  69. bInited = TRUE;
  70. return PRT_OK;
  71. }
  72. void LiveResource::Uninit(bool force) {
  73. CriticalSection::Owner lock(dataLocker);
  74. if(bInited || force) {
  75. delete [] A_currBlock;
  76. delete [] V_currBlock;
  77. delete [] tmpBlockData;
  78. A_currBlock = V_currBlock = NULL;
  79. tmpBlockData = NULL;
  80. if(blockMapArray) {
  81. for(UINT i = 0; i < blockMapSize; ++i) {
  82. if(blockMapArray[i] != UINT_MAX)
  83. comm->g_bufferMgr.EraseIndex(blockMapArray[i]);
  84. }
  85. }
  86. UninitEx();
  87. bInited = FALSE;
  88. }
  89. }
  90. P2P_RETURN_TYPE LiveResource::InitBroadcastMember(float bitRate) {
  91. this->bitRate = bitRate; // 码率
  92. memset(&spUpdate, 0, sizeof(SPUpdate));
  93. // 当前视频/音频块的数据
  94. if(!A_currBlock)
  95. A_currBlock = new BYTE[BLOCK_SIZE];
  96. if(!V_currBlock)
  97. V_currBlock = new BYTE[BLOCK_SIZE];
  98. if(!tmpBlockData)
  99. tmpBlockData = new BYTE[BLOCK_SIZE];
  100. if(!A_currBlock || !V_currBlock || !tmpBlockData)
  101. return PRT_ALLOC;
  102. A_currBlockID = V_currBlockID = UINT_MAX;
  103. A_leftDataInCurrBlock = V_leftDataInCurrBlock = 0;
  104. A_lastSampleTime = V_lastSampleTime = 0;
  105. A_last_OriginTime = V_last_OriginTime = 0;
  106. A_lastGetSampleFailedTime = V_lastGetSampleFailedTime = 0;
  107. programStartTime = 0;
  108. programState = PS_BOTH_BEGINS;
  109. totalBufferCount = 0;
  110. totalBufferTime  = 0;
  111. mediaArray.Clear();
  112. V_sentArray.Clear();
  113. A_sentArray.Clear();
  114. // 至少缓冲10块才能开始播放
  115. blocks4Play = max(static_cast<UINT>(TIME_FOR_PLAY*bitRate*1024/BLOCK_SIZE), 10);
  116. comm->logFile.StatusOut("blocks4play = %d. ", blocks4Play);
  117. return PRT_OK;
  118. }
  119. P2P_RETURN_TYPE LiveResource::LoadSample(
  120. SampleHeader& header, // Sample头
  121. PBYTE& sampleData, // Sample数据
  122. UINT sampleOff, // 已经读取的长度
  123. const UINT maxSize, // Sample最大长度
  124. const bool isAudio, // 视频还是音频
  125. bool& bMediaTypeSample // 是否媒体类型的特殊Sample
  126. )
  127. {
  128. UINT& currBlockID = isAudio ? A_currBlockID : V_currBlockID;
  129. BYTE *currBlock = isAudio ? A_currBlock : V_currBlock;
  130. UINT& leftDataInCurrBlock = isAudio ? A_leftDataInCurrBlock : V_leftDataInCurrBlock;
  131. MediaArray& sentArray = isAudio ? A_sentArray: V_sentArray;
  132. bMediaTypeSample = false;
  133. // 尚未设置开始播放的位置
  134. if(currBlockID == UINT_MAX)
  135. return PRT_PROGRAM_SYNC;
  136. while(0 == leftDataInCurrBlock) { // not data in current block, load next
  137. // 读取当前块数据
  138. UINT bSize = 0;
  139. P2P_RETURN_TYPE ret = GetBlock(currBlockID, bSize, currBlock);
  140. if(ret < PRT_OK)
  141. return ret;
  142. assert(bSize <= BLOCK_SIZE);
  143. // 如果此块的媒体类型还没有提交给上层,那么首先返回媒体类型
  144. if(!sentArray.FindBlock(currBlockID)) {
  145. MediaInterval mInterval;
  146. if(!mediaArray.GetInterval(currBlockID, mInterval)) {
  147. // 还没有下载到当前块的媒体类型
  148. return PRT_PROGRAM_SYNC;
  149. }
  150. comm->logFile.StatusOut("Post %s Media Type[%d, %d)) @ %d.", 
  151. isAudio?"Audio":"Video", mInterval.start, mInterval.start+mInterval.size, currBlockID);
  152. // 在sample中填入媒体类型数据
  153. header.start = header.length = 0;
  154. header.bSyncPoint = 1;
  155. header.bAudioSample = isAudio;
  156. if(isAudio) {
  157. memcpy(sampleData, &mInterval.audioType, sizeof(mInterval.audioType));
  158. memcpy(sampleData+sizeof(mInterval.audioType), mInterval.audioData, mInterval.audioType.cbFormat);
  159. header.size = sizeof(mInterval.audioType) + mInterval.audioType.cbFormat;
  160. }
  161. else {
  162. memcpy(sampleData, &mInterval.videoType, sizeof(mInterval.videoType));
  163. memcpy(sampleData+sizeof(mInterval.videoType), mInterval.videoData, mInterval.videoType.cbFormat);
  164. header.size = sizeof(mInterval.videoType) + mInterval.videoType.cbFormat;
  165. }
  166. assert(header.size >= sizeof(MediaType));
  167. if(!sentArray.AddInterval(mInterval))
  168. assert(0);
  169. // video or audio stopped
  170. if(isAudio && mInterval.audioType.cbFormat == 0)
  171. A_currBlockID = UINT_MAX;
  172. if(!isAudio && mInterval.videoType.cbFormat == 0)
  173. V_currBlockID = UINT_MAX;
  174. bMediaTypeSample = true;
  175. return PRT_OK;
  176. }
  177. currBlockID++;
  178. // 此Block从完整的Sample开始, 或许是新的节目开始了,确认一下
  179. if(IsFirstBlockOfNewProgram(currBlock)) {
  180. // 获取此块对应的编码格式,如果暂时没有,则返回同步中的消息
  181. MediaInterval mInterval;
  182. if(!mediaArray.GetInterval(currBlockID-1, mInterval)) {
  183. currBlockID--;
  184. assert(0);
  185. return PRT_PROGRAM_SYNC;
  186. }
  187. comm->logFile.StatusOut("New Program %d!", currBlockID-1);
  188.             /*
  189.             if(!mInterval.audioType.bThisPinOnly && !mInterval.videoType.bThisPinOnly) {
  190. // 有音频和视频,准备同步过程
  191. if(programState == PS_BOTH_BEGINS)
  192. programState = (isAudio?PS_AUDIO_BEGINS:PS_VIDEO_BEGINS); // 进入同步阶段
  193. else if(isAudio) {
  194. if(programState == PS_VIDEO_BEGINS)
  195. programState = PS_BOTH_BEGINS; // 发现视频已经在等待音频了,那么同步结束,开始播放
  196. else
  197. assert(0); // 音频正在同步中,不可能又读取了新的Block
  198. }
  199. else {
  200. if(programState == PS_AUDIO_BEGINS) // 发现音频已经在等待视频了,那么同步结束,开始播放
  201. programState = PS_BOTH_BEGINS;
  202. else
  203. assert(0); // 视频正在同步中,不可能有读取了新的Block
  204. }
  205. }
  206. if(programState == PS_BOTH_BEGINS) {
  207. // 同步结束,选择节目开始时间
  208. if(mInterval.videoType.bThisPinOnly) {
  209. programStartTime = V_lastSampleTime+TIME_BETWEEN_PROGRAM; // 单路视频
  210. }
  211. // 有视频/音频两路的情况下,选择音频作为新节目开始的时间.
  212. comm->logFile.StatusOut("Program Start Old %I64d.", programStartTime);
  213. programStartTime = A_lastSampleTime+TIME_BETWEEN_PROGRAM;
  214. comm->logFile.StatusOut("Program Start New %I64d.", programStartTime);
  215. }
  216.             */
  217. // 移动到第一个真正的Sample(非节目开头的标志Sample)的位置
  218. sampleOff = 0;
  219. leftDataInCurrBlock = BLOCK_SIZE-sizeof(UINT)*2-sizeof(SampleHeader);
  220. break;
  221. }
  222. // 第4~8个字节是first sample offset
  223. UINT sampleOffset = *((UINT*)currBlock+1);
  224. if(sampleOffset != UINT_MAX && (sampleOffset < sizeof(UINT)*2 || sampleOffset > BLOCK_SIZE)) {
  225. assert(0);
  226. // 删除这个错误的Block,并且跳过这个Block
  227. DelBlock(currBlockID-1);
  228. leftDataInCurrBlock = 0;
  229. sampleOff = 0;
  230. continue; // 错误的SampleOffset,抛弃当前块
  231. }
  232. // TODO: 由于CaptureServer的一个BUG,这里作一个修正,随着所有CaptureServer的更新,这里可以去除。 2005.04.18
  233. if(sampleOffset == BLOCK_SIZE)
  234. sampleOffset = UINT_MAX;
  235. if(sampleOff == 0) { // 开始读取新的Sample
  236. if(sampleOffset == UINT_MAX)
  237. continue; // 新的Sample不在当前Block中,继续寻找下一个
  238. else 
  239. leftDataInCurrBlock = BLOCK_SIZE-sampleOffset; // 新的Sample位置
  240. }
  241. else { // 继续读取剩余的数据
  242. leftDataInCurrBlock = BLOCK_SIZE-sizeof(UINT)*2; 
  243. if(!(sampleOffset==UINT_MAX || sampleOff < sizeof(SampleHeader) || sampleOffset == sizeof(UINT)*2+header.size-sampleOff)) {
  244. char* temp = NULL;
  245. MD5 md5(reinterpret_cast<BYTE*>(currBlock), BLOCK_SIZE);
  246. temp = md5.hex_digest();
  247. comm->logFile.StatusOut("Bad Block %d(%s).", currBlockID-1, temp);
  248. delete [] temp;
  249. assert(0);
  250. // 删除这个错误的Block,并且跳过这个Block
  251. DelBlock(currBlockID-1);
  252. leftDataInCurrBlock = 0;
  253. sampleOff = 0;
  254. continue;
  255. }
  256. }
  257. assert(leftDataInCurrBlock <= BLOCK_SIZE);
  258. break;
  259. }
  260. if(programState != PS_BOTH_BEGINS) { // 正在同步,应该可以投出类型数据
  261. if(!isAudio) {
  262. if(programState == PS_VIDEO_BEGINS)
  263. return PRT_PROGRAM_SYNC; // 视频正在等待同步,暂时不返回数据
  264. //else
  265. // 音频正在同步,不影响视频,所以继续
  266. }
  267. else {
  268. if(programState == PS_AUDIO_BEGINS)
  269. return PRT_PROGRAM_SYNC; // 音频正在等待同步,暂时不返回数据
  270. //else
  271. // 视频正在同步,不影响音频,所以继续
  272. }
  273. }
  274. BYTE* startOff = currBlock+(BLOCK_SIZE - leftDataInCurrBlock);
  275. // 尝试读取SampleHeader,直到读取了sizeof(SampleHeader)个字节,即dataOff == sizeof(SampleHeader)
  276. if(sampleOff < sizeof(SampleHeader)) {
  277. if(leftDataInCurrBlock < sizeof(SampleHeader)-sampleOff) {
  278. // 数据仍然不足sizeof(SampleHeader),继续读取下一个块
  279. memcpy((BYTE*)&header + sampleOff, startOff, leftDataInCurrBlock);
  280. sampleOff += leftDataInCurrBlock;
  281. leftDataInCurrBlock = 0;
  282. return LoadSample(header, sampleData, sampleOff, maxSize, isAudio, bMediaTypeSample);
  283. }
  284. else {
  285. // 数据已经足够,读取完整的sample header
  286. memcpy((BYTE*)&header + sampleOff, startOff, sizeof(SampleHeader)-sampleOff);
  287. assert(header.size >= sizeof(SampleHeader) && header.size <= maxSize);
  288. if(header.size < sizeof(SampleHeader) || header.size > maxSize) {
  289. // 错误的Header,抛弃当前块,重新读取新的Sample
  290. sampleOff = 0;
  291. leftDataInCurrBlock = 0;
  292. return LoadSample(header, sampleData, sampleOff, maxSize, isAudio, bMediaTypeSample);
  293. }
  294. leftDataInCurrBlock -= (sizeof(SampleHeader)-sampleOff);
  295. sampleOff = sizeof(SampleHeader);
  296. }
  297. }
  298. startOff = currBlock+(BLOCK_SIZE - leftDataInCurrBlock);
  299. // 读取SampleHeader之外的数据
  300. if(sampleOff >= sizeof(SampleHeader)) {
  301. if(leftDataInCurrBlock < header.size-sampleOff) {
  302. // 当前块中剩下的数据不足,继续读取下一块
  303. if(sampleData)
  304. memcpy(sampleData+sampleOff-sizeof(SampleHeader), startOff, leftDataInCurrBlock);
  305. sampleOff += leftDataInCurrBlock;
  306. leftDataInCurrBlock = 0;
  307. return LoadSample(header, sampleData, sampleOff, maxSize, isAudio, bMediaTypeSample);
  308. }
  309. else {
  310. // 读取到完整的Sample
  311. if(sampleData)
  312. memcpy(sampleData+sampleOff-sizeof(SampleHeader), startOff, header.size-sampleOff);
  313. leftDataInCurrBlock -= (header.size-sampleOff);
  314. }
  315. }
  316. assert(leftDataInCurrBlock <= BLOCK_SIZE);
  317. return PRT_OK;
  318. }
  319. P2P_RETURN_TYPE LiveResource::GetData(
  320.   SampleHeader& header, // out, 数据头
  321.   PBYTE& pData, // out, 存储数据的缓冲区
  322.   const UINT maxSize, // in, 缓冲区的长度
  323.   const bool bAudio, // in, 获取音频还是视频
  324.   const bool bKeySample // in, 是否寻找关键帧
  325.   )
  326. {
  327. if(!bInited) // not started
  328. return PRT_NOT_INIT;
  329. CriticalSection::Owner lock(dataLocker);
  330. bool bMediaTypeSample = false;
  331. for(;;) {
  332. for(;;) {
  333. P2P_RETURN_TYPE ret = LoadSample(header, pData, 0, maxSize, bAudio, bMediaTypeSample);
  334. if(ret < PRT_OK) {
  335. if(bAudio)
  336. A_lastGetSampleFailedTime = timeGetTime(); // 记录GetSample失败的时间
  337. else
  338. V_lastGetSampleFailedTime = timeGetTime(); // 记录GetSample失败的时间
  339. comm->logFile.StatusOut("GetData failed. %d", ret);
  340. return ret;
  341. }
  342. // 如果是目标类型,则完成寻找
  343. if(bAudio == header.bAudioSample)
  344. break;
  345. }
  346. // 是否正在寻找视频的关键Sample,如果是,当前Sample是目标Sample吗?
  347. if(!bKeySample || (!bAudio && header.bSyncPoint))
  348. break;
  349. }
  350. if(bAudio)
  351. A_lastGetSampleFailedTime = 0; // GetSample成功了
  352. else
  353. V_lastGetSampleFailedTime = 0; // GetSample成功了
  354. if(!bMediaTypeSample) {
  355. A_last_OriginTime = header.start+header.length;
  356. // 加上节目开始的时间
  357. header.start += programStartTime;
  358. //assert(header.start+1*10000000 >= (isAudio?A_lastSampleTime:V_lastSampleTime));
  359. //assert(header.bDiscontinuity == 0);
  360. header.bDiscontinuity = 0;
  361. // 记录最近一个Sample的时间
  362. if(bAudio)
  363. A_lastSampleTime = header.start;
  364. else
  365. V_lastSampleTime = header.start;
  366. comm->logFile.StatusOut("%s Sample Time %I64d(%I64d) at Block %d", bAudio?"Audio":"Video", header.start, 
  367. header.start - programStartTime, bAudio?A_currBlockID-1:V_currBlockID-1);
  368. }
  369. return PRT_OK;
  370. }
  371. // 存储Block,在存储之前检查此Block及其后面的一个Block是否正确
  372. P2P_RETURN_TYPE LiveResource::PutBlock(UINT blockID, UINT blockSize, PBYTE data) {
  373. if(!bInited) // not started
  374. return PRT_NOT_INIT;
  375. CriticalSection::Owner lock(dataLocker);
  376.     assert(mediaArray.FindBlock(blockID));
  377. P2P_RETURN_TYPE ret = PRT_OK;
  378. UINT unfinishedSize = 0;
  379. UINT tmpSize = 0;
  380. // 1. 读取blockID-1的数据,以便检查blockID块的数据是否正确
  381. ret = GetBlock(blockID-1, tmpSize, tmpBlockData);
  382. if(ret != PRT_OK && ret != PRT_BLOCK_NOTFOUND) {// 如果找到或者没找到此块都是正常的,但是其他返回值就不正常了
  383. assert(0);
  384. return ret;
  385. }
  386. if(ret != PRT_BLOCK_NOTFOUND) {
  387. // 2. 获取blockID-1块最后一个Sample,在blockID中的剩余长度
  388. if(!GetUnfinishedSampleSize(tmpBlockData, unfinishedSize)) {
  389. DelBlock(blockID-1); // 删除错误的blockID-1块
  390. }
  391. else if(unfinishedSize != UINT_MAX) {
  392. // 3. 根据剩余长度检查blockID块数据是否正确
  393. UINT sampleOffset = *((UINT*)data + 1);
  394. // TODO: 由于CaptureServer的一个BUG,这里作一个修正,随着所有CaptureServer的更新,这里可以去除。 2005.04.18
  395. if(sampleOffset == BLOCK_SIZE)
  396. sampleOffset = UINT_MAX;
  397. if(sampleOffset != unfinishedSize+sizeof(UINT)*2) {
  398. if(sampleOffset == UINT_MAX && unfinishedSize > BLOCK_SIZE) {
  399. ; // blockID块被完全跨越,数据应该是正确的
  400. }
  401. else if(!IsFirstBlockOfNewProgram(data)) {
  402. assert(0);
  403. return PRT_BAD_BLOCK; // 不是新节目,blockID块数据错误,直接错误
  404. }
  405. }
  406. }
  407. // 4. 读取blockID+1块
  408. ret = GetBlock(blockID+1, tmpSize, tmpBlockData);
  409. if(ret != PRT_OK && ret != PRT_BLOCK_NOTFOUND)// 如果找到或者没找到此块都是正常的,但是其他返回值就不正常了
  410. return ret;
  411. if(ret != PRT_BLOCK_NOTFOUND) {
  412. // 5. 获取blockID块最后一个Sample,在blockID+1中的剩余长度
  413. if(!GetUnfinishedSampleSize(data, unfinishedSize))
  414. return PRT_OK; // blockID块数据错误,直接返回
  415. else if(unfinishedSize != UINT_MAX) {
  416. // 6. 根据剩余长度检查blockID+1块数据是否正确
  417. UINT sampleOffset = *((UINT*)tmpBlockData + 1);
  418. // TODO: 由于CaptureServer的一个BUG,这里作一个修正,随着所有CaptureServer的更新,这里可以去除。 2005.04.18
  419. if(sampleOffset == BLOCK_SIZE)
  420. sampleOffset = UINT_MAX;
  421. if(sampleOffset != unfinishedSize+sizeof(UINT)*2) {
  422. if(sampleOffset == UINT_MAX && unfinishedSize > BLOCK_SIZE) {
  423. ; // blockID+1块被完全跨越,数据应该是正确的
  424. }
  425. else if(!IsFirstBlockOfNewProgram(tmpBlockData)) {
  426. assert(0);
  427. DelBlock(blockID+1); // 删除错误的blockID+1块, 没有记录此块来自哪个NP
  428. }
  429. }
  430. }
  431. }
  432. }
  433. // 数据正确,存储此Block
  434. return BaseResource::PutBlock(blockID, blockSize, data);
  435. }
  436. // 获取此Block末尾一个Sample被截断后,在下一个Block所残留的长度,返回值表示此Block是否数据正确
  437. bool LiveResource::GetUnfinishedSampleSize(PBYTE& blockData, UINT& unfinishedSize) {
  438. UINT sampleOffset = *((UINT*)blockData + 1);
  439. if(sampleOffset == UINT_MAX) {
  440. unfinishedSize = UINT_MAX;
  441. return true; // 没法检查,因为sample跨越了整个block,放过这种情况吧
  442. }
  443. else if(sampleOffset < sizeof(UINT)*2 || sampleOffset > BLOCK_SIZE) {
  444. assert(0);
  445. return false; // 数据错误
  446. }
  447. SampleHeader* header = (SampleHeader*)(blockData+sampleOffset);
  448. while(1) {
  449. if(sampleOffset+sizeof(UINT) > BLOCK_SIZE) {
  450. // SampleHeader中的Size尚未读全,没法确定残留的长度,放过这种情况
  451. unfinishedSize = UINT_MAX;
  452. return true;
  453. }
  454. else if(sampleOffset + header->size >= BLOCK_SIZE) {
  455. unfinishedSize = sampleOffset + header->size - BLOCK_SIZE; // 这就是残留的长度
  456. if(unfinishedSize > 1000000)
  457. assert(0);
  458. return true;
  459. }
  460. sampleOffset += header->size;
  461. header = (SampleHeader*)(blockData+sampleOffset);
  462. }
  463. assert(0);
  464. return false;
  465. }
  466. // 检查此Block是否新节目的第一块
  467. bool LiveResource::IsFirstBlockOfNewProgram(PBYTE& blockData) {
  468. UINT sampleOffset = *((UINT*)blockData + 1);
  469. if(sampleOffset == sizeof(UINT)*2) {
  470. SampleHeader* header = (SampleHeader*)(blockData+sizeof(UINT)*2);
  471. // 新节目的第一个Sample格式特殊,具体值如下判断
  472. if(header->length == 0xffffffff && header->start == 0xffffffffffffffff && header->size == sizeof(SampleHeader))
  473. return true;
  474. }
  475. return false;
  476. }
  477. UINT16 LiveResource::GetBufferCount() {
  478. if(totalBufferCount >= 0xffff)
  479. return 0xffff;
  480. return static_cast<UINT16>(totalBufferCount);
  481. }
  482. UINT16 LiveResource::GetBufferTime() {
  483. if(totalBufferTime/1000 >= 0xffff)
  484. return 0xffff;
  485. return static_cast<UINT16>(totalBufferTime/1000);
  486. }
  487. UINT16 LiveResource::GetBufferingTime() {
  488. // 如果正在缓冲的过程中,那么把到目前为止的时间也要计算上
  489. DWORD lastGetSampleFailedTime = A_lastGetSampleFailedTime;
  490. if(lastGetSampleFailedTime == 0)
  491. lastGetSampleFailedTime = V_lastGetSampleFailedTime;
  492. if(lastGetSampleFailedTime != 0) {
  493. UINT bufTime = timeGetTime()-lastGetSampleFailedTime;
  494. if(bufTime/1000 >= 0xffff)
  495. return 0xffff;
  496. return static_cast<UINT16>(bufTime/1000);
  497. }
  498. return 0;
  499. }
  500. void LiveResource::SetSPUpdate(const SPUpdate& update, BYTE sum) {
  501. #ifdef _DEBUG
  502. // TODO: 测试使用,正式版本一定要去掉
  503. //spUpdate.minBlockID = spUpdate.maxBlockID = 0;
  504. #endif
  505. // 是否尚未收到过SPUpdate
  506. bool bNoFirstSPUpdate = (spUpdate.minBlockID == 0 && spUpdate.maxBlockID == 0);
  507. spUpdate = update;
  508. spUpdateSum = sum;
  509. // 是否需要重新设置播放位置
  510. bool bNeedResetPlayingBlock = bNoFirstSPUpdate;
  511. // 如果播放位置比SP拥有的最小Block还小,就自动调整播放位置
  512. if(GetPlayingBlock() < spUpdate.minBlockID)
  513. bNeedResetPlayingBlock = true;
  514. // 从TIME_BEGIN_PLAY秒钟前的位置开始下载播放
  515. if(bNeedResetPlayingBlock) {
  516. const float SECPERBLOCK = bitRate*1024/BLOCK_SIZE; // 每块包含的大致时间长度
  517. const UINT BLOCK_BEFORE = static_cast<UINT>(TIME_BEGIN_PLAY*SECPERBLOCK); // 提前的块数
  518. if(spUpdate.maxBlockID >= spUpdate.minBlockID+BLOCK_BEFORE)
  519. SetPlayingBlock(spUpdate.maxBlockID-BLOCK_BEFORE);
  520. else
  521. SetPlayingBlock(spUpdate.minBlockID);
  522. }
  523. }
  524. BOOL LiveResource::SeekToTime(LONGLONG& targetTime) {
  525. comm->logFile.StatusOut("Begin Seeking......to %ds %dms", targetTime/10000000, targetTime/10000);
  526. if(!bInited)
  527. return FALSE;
  528. if(targetTime == 0) // reset to begin. do nothing.
  529. return TRUE;
  530. if((spUpdate.maxKeySample > spUpdate.minKeySample) && 
  531. (targetTime >= spUpdate.minKeySample) && (targetTime <= spUpdate.maxKeySample) && 
  532. spUpdate.maxBlockID > spUpdate.minBlockID) 
  533. {
  534. double temp = ((double)(targetTime-spUpdate.minKeySample))/(spUpdate.maxKeySample-spUpdate.minKeySample);
  535. UINT targetBlockID = static_cast<UINT>(temp*(spUpdate.maxBlockID-spUpdate.minBlockID))+spUpdate.minBlockID;
  536. SetPlayingBlock(targetBlockID);
  537. }
  538. else {
  539. comm->logFile.StatusOut("Bad seeking position!");
  540. return FALSE;
  541. }
  542. return TRUE;
  543. }
  544. // 添加一个区间对应的媒体类型
  545. void LiveResource::AddMediaInterval(const MediaInterval& mi) {
  546. comm->logFile.StatusOut("Got MediaType of [%d, %d).", mi.start, mi.start+mi.size);
  547.     // 是否发生了直播改变编码格式
  548.     bool bLiveChangeMediaData = false;
  549.     if(!mediaArray.AddInterval(mi, &bLiveChangeMediaData)) {
  550. assert(0);
  551.         return;
  552.     }
  553.     if(bLiveChangeMediaData) {
  554.         // 清除NP连接发送媒体类型区间的记录
  555.         comm->p2pMgr.ClearSentMediaArray();
  556.         // 记录不再向上层提交的媒体类型
  557.         MediaInterval temp;
  558.         if(A_sentArray.FindBlock(A_currBlockID)) {
  559.             if(mediaArray.GetInterval(A_currBlockID, temp)) {
  560.                 A_sentArray.Clear();
  561.                 A_sentArray.AddInterval(temp);
  562.             }
  563.         }
  564.         if(V_sentArray.FindBlock(V_currBlockID)) {
  565.             if(mediaArray.GetInterval(V_currBlockID, temp)) {
  566.                 V_sentArray.Clear();
  567.                 V_sentArray.AddInterval(temp);
  568.             }
  569.         }
  570.     }
  571. }
  572. // 获取一个Block所在区间的媒体类型
  573. bool LiveResource::GetMediaInterval(const UINT blockID, MediaInterval& mi) {
  574. return mediaArray.GetInterval(blockID, mi);
  575. }
  576. BOOL LiveResource::SetPlayingBlock(UINT blockID) {
  577. if(blockID == UINT_MAX)
  578. return FALSE;
  579. CriticalSection::Owner lock(dataLocker);
  580. // 设置开始播放的位置
  581. A_currBlockID = V_currBlockID = blockID;
  582. A_leftDataInCurrBlock = V_leftDataInCurrBlock = 0;
  583. comm->logFile.StatusOut("SetPlayingBlock %d. spupdate.maxblockID %d", blockID, spUpdate.maxBlockID);
  584. return TRUE;
  585. }
  586. // 对于直播, 取得视频音频中比较大(小)的那个BlockID, 当然,如果是单音频或者单视频的,就取得相应的BlockID
  587. UINT LiveResource::GetPlayingBlock(bool max) {
  588. if(V_currBlockID == UINT_MAX)
  589. return A_currBlockID;
  590. if(A_currBlockID == UINT_MAX)
  591. return V_currBlockID;
  592. if(max)
  593. return max(V_currBlockID, A_currBlockID);
  594. return min(V_currBlockID, A_currBlockID);
  595. };
  596. int LiveResource::GetBufferPercent() {
  597. // 要保证blocks4Play不等于0,否则此处一定返回100
  598. if(blocks4Play == 0)
  599. return 100;
  600. UINT nextBlock = GetPlayingBlock();
  601. return min(100, allIntervals.GetCountInInterval(nextBlock, blocks4Play)*100/blocks4Play);
  602. }
  603. bool LiveResource::EnlargeBuffer() {
  604. totalBufferCount++;
  605. DWORD lastGetSampleFailedTime = A_lastGetSampleFailedTime;
  606. if(lastGetSampleFailedTime == 0)
  607. lastGetSampleFailedTime = V_lastGetSampleFailedTime;
  608. if(lastGetSampleFailedTime != 0)
  609. totalBufferTime += (timeGetTime() - lastGetSampleFailedTime);
  610. if(blocks4Play >= static_cast<UINT>(180*bitRate*1024/BLOCK_SIZE)) {
  611. comm->logFile.StatusOut("Delay more than 3 minutes, do not add.");
  612. return false;
  613. }
  614. comm->logFile.StatusOut("live Pause! Add 50%% time for buffer.");
  615. blocks4Play = static_cast<UINT>(blocks4Play*1.5f);
  616. return true;
  617. }
  618. void LiveResource::PrintStatus() {
  619. comm->logFile.StatusOut("CurrBlock: A%d/V%d, Continued: %d/%d. BlockRange: %d/%d, SPUpdate: %d/%d, ntBuffer Percent: %d%%. BufferCount: %d, BufferTime: %ds, curr Buffer: %ds.", 
  620. A_currBlockID, V_currBlockID, 
  621. allIntervals.GetContinousCount(GetPlayingBlock()), 
  622. allIntervals.GetCountInInterval(GetPlayingBlock(), UINT_MAX), 
  623. GetMinBlockID(), GetMaxBlockID(), 
  624. spUpdate.minBlockID, spUpdate.maxBlockID, 
  625. GetBufferPercent(), GetBufferCount(), 
  626. GetBufferTime(), GetBufferingTime());
  627. }
  628. void LiveResource::SetDefaultCP() {
  629. // 直播的默认CP地址就是和SP相同的IP
  630. if(spIPList) {
  631. PeerInfoWithAddr nAddr;
  632. nAddr.outerIP.sin_addr.s_addr = spIPList[0].sin_addr.s_addr;
  633. nAddr.subnetIP.sin_addr.s_addr = 0xffffffff;
  634. nAddr.subnetIP.sin_port = htons(CP4NP_PORT);
  635. nAddr.isCachePeer = true;
  636. nAddr.layer = 0;
  637. comm->p2pMgr.AddPeerInfo(nAddr);
  638. comm->logFile.StatusOut("Choose Default CP %s.", comm->p2pMgr.FormatIPAddress(nAddr));
  639. }
  640. };
  641. // 获取节目名字
  642. string LiveResource::GetProgramName() {
  643. MediaInterval mInterval;
  644. if(!mediaArray.GetInterval(GetPlayingBlock(), mInterval))
  645. return "";
  646. if(!mInterval.pname || !mInterval.pnamesize)
  647. return "";
  648. string temp = mInterval.pname;
  649. return temp;
  650. }
  651. // 获取节目时间长度
  652. UINT32 LiveResource::GetProgramTimeInSeconds() {
  653. MediaInterval mInterval;
  654. if(!mediaArray.GetInterval(GetPlayingBlock(), mInterval))
  655. return 0;
  656. return mInterval.progtime;
  657. }
  658. // 获取频道名字
  659. string LiveResource::GetChannelName() {
  660. MediaInterval mInterval;
  661. if(!mediaArray.GetInterval(GetPlayingBlock(), mInterval))
  662. return "";
  663. if(!mInterval.cname || !mInterval.cnamesize)
  664. return "";
  665. string temp = mInterval.cname;
  666. return temp;
  667. }
  668. }