LiveResource.cpp
资源名称:p2p_vod.rar [点击查看]
上传用户:liguizhu
上传日期:2015-11-01
资源大小:2422k
文件大小:25k
源码类别:
P2P编程
开发平台:
Visual C++
- /*
- * 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 ".liveresource.h"
- #include "Communicator.h"
- #include "BufferMgr.h"
- namespace NPLayer1 {
- LiveResource::LiveResource(Communicator*c ) :
- BaseResource(c), A_currBlock(NULL), V_currBlock(NULL), tmpBlockData(NULL)
- {
- }
- LiveResource::~LiveResource(void) {
- Uninit(false);
- }
- // 第一次开始下载的初始化
- P2P_RETURN_TYPE LiveResource::Init(
- string resname, // 资源名
- string hashcode, // 资源的Hash码
- string strSPList, // SuperPeer列表的IP地址
- float bitRate) // 频道的码率
- {
- CriticalSection::Owner lock(dataLocker);
- try {
- // 不能重复初始化
- if(bInited)
- throw PRT_DUP_INIT;
- this->resname = resname;
- this->hashcode = hashcode;
- bufferMgr = &comm->g_bufferMgr;
- // 直播资源未知大小,需要的磁盘空间是小于缓冲文件大小的某个固定值
- // DEFAULT_SPACE必须保证整除BLOCK_SIZE
- blockMapSize = DEFAULT_SPACE/BLOCK_SIZE;
- // 初始化数组
- blockMapArray = new UINT[blockMapSize];
- blockIDArray = new UINT[blockMapSize];
- if(!blockMapArray || !blockIDArray)
- throw PRT_ALLOC;
- // 初始化数组所有成员为UINT_MAX
- fill(blockMapArray, blockMapArray+blockMapSize, UINT_MAX);
- fill(blockIDArray, blockIDArray+blockMapSize, UINT_MAX);
- P2P_RETURN_TYPE ret = ParseSPList(strSPList);
- if(ret != PRT_OK)
- throw ret;
- ret = InitBroadcastMember(bitRate);
- if(ret < PRT_OK)
- throw ret;
- }
- catch (P2P_RETURN_TYPE ret) {
- comm->logFile.StatusOut("Init Res Error!");
- Uninit(true);
- return ret;
- }
- bInited = TRUE;
- return PRT_OK;
- }
- void LiveResource::Uninit(bool force) {
- CriticalSection::Owner lock(dataLocker);
- if(bInited || force) {
- delete [] A_currBlock;
- delete [] V_currBlock;
- delete [] tmpBlockData;
- A_currBlock = V_currBlock = NULL;
- tmpBlockData = NULL;
- if(blockMapArray) {
- for(UINT i = 0; i < blockMapSize; ++i) {
- if(blockMapArray[i] != UINT_MAX)
- comm->g_bufferMgr.EraseIndex(blockMapArray[i]);
- }
- }
- UninitEx();
- bInited = FALSE;
- }
- }
- P2P_RETURN_TYPE LiveResource::InitBroadcastMember(float bitRate) {
- this->bitRate = bitRate; // 码率
- memset(&spUpdate, 0, sizeof(SPUpdate));
- // 当前视频/音频块的数据
- if(!A_currBlock)
- A_currBlock = new BYTE[BLOCK_SIZE];
- if(!V_currBlock)
- V_currBlock = new BYTE[BLOCK_SIZE];
- if(!tmpBlockData)
- tmpBlockData = new BYTE[BLOCK_SIZE];
- if(!A_currBlock || !V_currBlock || !tmpBlockData)
- return PRT_ALLOC;
- A_currBlockID = V_currBlockID = UINT_MAX;
- A_leftDataInCurrBlock = V_leftDataInCurrBlock = 0;
- A_lastSampleTime = V_lastSampleTime = 0;
- A_last_OriginTime = V_last_OriginTime = 0;
- A_lastGetSampleFailedTime = V_lastGetSampleFailedTime = 0;
- programStartTime = 0;
- programState = PS_BOTH_BEGINS;
- totalBufferCount = 0;
- totalBufferTime = 0;
- mediaArray.Clear();
- V_sentArray.Clear();
- A_sentArray.Clear();
- // 至少缓冲10块才能开始播放
- blocks4Play = max(static_cast<UINT>(TIME_FOR_PLAY*bitRate*1024/BLOCK_SIZE), 10);
- comm->logFile.StatusOut("blocks4play = %d. ", blocks4Play);
- return PRT_OK;
- }
- P2P_RETURN_TYPE LiveResource::LoadSample(
- SampleHeader& header, // Sample头
- PBYTE& sampleData, // Sample数据
- UINT sampleOff, // 已经读取的长度
- const UINT maxSize, // Sample最大长度
- const bool isAudio, // 视频还是音频
- bool& bMediaTypeSample // 是否媒体类型的特殊Sample
- )
- {
- UINT& currBlockID = isAudio ? A_currBlockID : V_currBlockID;
- BYTE *currBlock = isAudio ? A_currBlock : V_currBlock;
- UINT& leftDataInCurrBlock = isAudio ? A_leftDataInCurrBlock : V_leftDataInCurrBlock;
- MediaArray& sentArray = isAudio ? A_sentArray: V_sentArray;
- bMediaTypeSample = false;
- // 尚未设置开始播放的位置
- if(currBlockID == UINT_MAX)
- return PRT_PROGRAM_SYNC;
- while(0 == leftDataInCurrBlock) { // not data in current block, load next
- // 读取当前块数据
- UINT bSize = 0;
- P2P_RETURN_TYPE ret = GetBlock(currBlockID, bSize, currBlock);
- if(ret < PRT_OK)
- return ret;
- assert(bSize <= BLOCK_SIZE);
- // 如果此块的媒体类型还没有提交给上层,那么首先返回媒体类型
- if(!sentArray.FindBlock(currBlockID)) {
- MediaInterval mInterval;
- if(!mediaArray.GetInterval(currBlockID, mInterval)) {
- // 还没有下载到当前块的媒体类型
- return PRT_PROGRAM_SYNC;
- }
- comm->logFile.StatusOut("Post %s Media Type[%d, %d)) @ %d.",
- isAudio?"Audio":"Video", mInterval.start, mInterval.start+mInterval.size, currBlockID);
- // 在sample中填入媒体类型数据
- header.start = header.length = 0;
- header.bSyncPoint = 1;
- header.bAudioSample = isAudio;
- if(isAudio) {
- memcpy(sampleData, &mInterval.audioType, sizeof(mInterval.audioType));
- memcpy(sampleData+sizeof(mInterval.audioType), mInterval.audioData, mInterval.audioType.cbFormat);
- header.size = sizeof(mInterval.audioType) + mInterval.audioType.cbFormat;
- }
- else {
- memcpy(sampleData, &mInterval.videoType, sizeof(mInterval.videoType));
- memcpy(sampleData+sizeof(mInterval.videoType), mInterval.videoData, mInterval.videoType.cbFormat);
- header.size = sizeof(mInterval.videoType) + mInterval.videoType.cbFormat;
- }
- assert(header.size >= sizeof(MediaType));
- if(!sentArray.AddInterval(mInterval))
- assert(0);
- // video or audio stopped
- if(isAudio && mInterval.audioType.cbFormat == 0)
- A_currBlockID = UINT_MAX;
- if(!isAudio && mInterval.videoType.cbFormat == 0)
- V_currBlockID = UINT_MAX;
- bMediaTypeSample = true;
- return PRT_OK;
- }
- currBlockID++;
- // 此Block从完整的Sample开始, 或许是新的节目开始了,确认一下
- if(IsFirstBlockOfNewProgram(currBlock)) {
- // 获取此块对应的编码格式,如果暂时没有,则返回同步中的消息
- MediaInterval mInterval;
- if(!mediaArray.GetInterval(currBlockID-1, mInterval)) {
- currBlockID--;
- assert(0);
- return PRT_PROGRAM_SYNC;
- }
- comm->logFile.StatusOut("New Program %d!", currBlockID-1);
- /*
- if(!mInterval.audioType.bThisPinOnly && !mInterval.videoType.bThisPinOnly) {
- // 有音频和视频,准备同步过程
- if(programState == PS_BOTH_BEGINS)
- programState = (isAudio?PS_AUDIO_BEGINS:PS_VIDEO_BEGINS); // 进入同步阶段
- else if(isAudio) {
- if(programState == PS_VIDEO_BEGINS)
- programState = PS_BOTH_BEGINS; // 发现视频已经在等待音频了,那么同步结束,开始播放
- else
- assert(0); // 音频正在同步中,不可能又读取了新的Block
- }
- else {
- if(programState == PS_AUDIO_BEGINS) // 发现音频已经在等待视频了,那么同步结束,开始播放
- programState = PS_BOTH_BEGINS;
- else
- assert(0); // 视频正在同步中,不可能有读取了新的Block
- }
- }
- if(programState == PS_BOTH_BEGINS) {
- // 同步结束,选择节目开始时间
- if(mInterval.videoType.bThisPinOnly) {
- programStartTime = V_lastSampleTime+TIME_BETWEEN_PROGRAM; // 单路视频
- }
- // 有视频/音频两路的情况下,选择音频作为新节目开始的时间.
- comm->logFile.StatusOut("Program Start Old %I64d.", programStartTime);
- programStartTime = A_lastSampleTime+TIME_BETWEEN_PROGRAM;
- comm->logFile.StatusOut("Program Start New %I64d.", programStartTime);
- }
- */
- // 移动到第一个真正的Sample(非节目开头的标志Sample)的位置
- sampleOff = 0;
- leftDataInCurrBlock = BLOCK_SIZE-sizeof(UINT)*2-sizeof(SampleHeader);
- break;
- }
- // 第4~8个字节是first sample offset
- UINT sampleOffset = *((UINT*)currBlock+1);
- if(sampleOffset != UINT_MAX && (sampleOffset < sizeof(UINT)*2 || sampleOffset > BLOCK_SIZE)) {
- assert(0);
- // 删除这个错误的Block,并且跳过这个Block
- DelBlock(currBlockID-1);
- leftDataInCurrBlock = 0;
- sampleOff = 0;
- continue; // 错误的SampleOffset,抛弃当前块
- }
- // TODO: 由于CaptureServer的一个BUG,这里作一个修正,随着所有CaptureServer的更新,这里可以去除。 2005.04.18
- if(sampleOffset == BLOCK_SIZE)
- sampleOffset = UINT_MAX;
- if(sampleOff == 0) { // 开始读取新的Sample
- if(sampleOffset == UINT_MAX)
- continue; // 新的Sample不在当前Block中,继续寻找下一个
- else
- leftDataInCurrBlock = BLOCK_SIZE-sampleOffset; // 新的Sample位置
- }
- else { // 继续读取剩余的数据
- leftDataInCurrBlock = BLOCK_SIZE-sizeof(UINT)*2;
- if(!(sampleOffset==UINT_MAX || sampleOff < sizeof(SampleHeader) || sampleOffset == sizeof(UINT)*2+header.size-sampleOff)) {
- char* temp = NULL;
- MD5 md5(reinterpret_cast<BYTE*>(currBlock), BLOCK_SIZE);
- temp = md5.hex_digest();
- comm->logFile.StatusOut("Bad Block %d(%s).", currBlockID-1, temp);
- delete [] temp;
- assert(0);
- // 删除这个错误的Block,并且跳过这个Block
- DelBlock(currBlockID-1);
- leftDataInCurrBlock = 0;
- sampleOff = 0;
- continue;
- }
- }
- assert(leftDataInCurrBlock <= BLOCK_SIZE);
- break;
- }
- if(programState != PS_BOTH_BEGINS) { // 正在同步,应该可以投出类型数据
- if(!isAudio) {
- if(programState == PS_VIDEO_BEGINS)
- return PRT_PROGRAM_SYNC; // 视频正在等待同步,暂时不返回数据
- //else
- // 音频正在同步,不影响视频,所以继续
- }
- else {
- if(programState == PS_AUDIO_BEGINS)
- return PRT_PROGRAM_SYNC; // 音频正在等待同步,暂时不返回数据
- //else
- // 视频正在同步,不影响音频,所以继续
- }
- }
- BYTE* startOff = currBlock+(BLOCK_SIZE - leftDataInCurrBlock);
- // 尝试读取SampleHeader,直到读取了sizeof(SampleHeader)个字节,即dataOff == sizeof(SampleHeader)
- if(sampleOff < sizeof(SampleHeader)) {
- if(leftDataInCurrBlock < sizeof(SampleHeader)-sampleOff) {
- // 数据仍然不足sizeof(SampleHeader),继续读取下一个块
- memcpy((BYTE*)&header + sampleOff, startOff, leftDataInCurrBlock);
- sampleOff += leftDataInCurrBlock;
- leftDataInCurrBlock = 0;
- return LoadSample(header, sampleData, sampleOff, maxSize, isAudio, bMediaTypeSample);
- }
- else {
- // 数据已经足够,读取完整的sample header
- memcpy((BYTE*)&header + sampleOff, startOff, sizeof(SampleHeader)-sampleOff);
- assert(header.size >= sizeof(SampleHeader) && header.size <= maxSize);
- if(header.size < sizeof(SampleHeader) || header.size > maxSize) {
- // 错误的Header,抛弃当前块,重新读取新的Sample
- sampleOff = 0;
- leftDataInCurrBlock = 0;
- return LoadSample(header, sampleData, sampleOff, maxSize, isAudio, bMediaTypeSample);
- }
- leftDataInCurrBlock -= (sizeof(SampleHeader)-sampleOff);
- sampleOff = sizeof(SampleHeader);
- }
- }
- startOff = currBlock+(BLOCK_SIZE - leftDataInCurrBlock);
- // 读取SampleHeader之外的数据
- if(sampleOff >= sizeof(SampleHeader)) {
- if(leftDataInCurrBlock < header.size-sampleOff) {
- // 当前块中剩下的数据不足,继续读取下一块
- if(sampleData)
- memcpy(sampleData+sampleOff-sizeof(SampleHeader), startOff, leftDataInCurrBlock);
- sampleOff += leftDataInCurrBlock;
- leftDataInCurrBlock = 0;
- return LoadSample(header, sampleData, sampleOff, maxSize, isAudio, bMediaTypeSample);
- }
- else {
- // 读取到完整的Sample
- if(sampleData)
- memcpy(sampleData+sampleOff-sizeof(SampleHeader), startOff, header.size-sampleOff);
- leftDataInCurrBlock -= (header.size-sampleOff);
- }
- }
- assert(leftDataInCurrBlock <= BLOCK_SIZE);
- return PRT_OK;
- }
- P2P_RETURN_TYPE LiveResource::GetData(
- SampleHeader& header, // out, 数据头
- PBYTE& pData, // out, 存储数据的缓冲区
- const UINT maxSize, // in, 缓冲区的长度
- const bool bAudio, // in, 获取音频还是视频
- const bool bKeySample // in, 是否寻找关键帧
- )
- {
- if(!bInited) // not started
- return PRT_NOT_INIT;
- CriticalSection::Owner lock(dataLocker);
- bool bMediaTypeSample = false;
- for(;;) {
- for(;;) {
- P2P_RETURN_TYPE ret = LoadSample(header, pData, 0, maxSize, bAudio, bMediaTypeSample);
- if(ret < PRT_OK) {
- if(bAudio)
- A_lastGetSampleFailedTime = timeGetTime(); // 记录GetSample失败的时间
- else
- V_lastGetSampleFailedTime = timeGetTime(); // 记录GetSample失败的时间
- comm->logFile.StatusOut("GetData failed. %d", ret);
- return ret;
- }
- // 如果是目标类型,则完成寻找
- if(bAudio == header.bAudioSample)
- break;
- }
- // 是否正在寻找视频的关键Sample,如果是,当前Sample是目标Sample吗?
- if(!bKeySample || (!bAudio && header.bSyncPoint))
- break;
- }
- if(bAudio)
- A_lastGetSampleFailedTime = 0; // GetSample成功了
- else
- V_lastGetSampleFailedTime = 0; // GetSample成功了
- if(!bMediaTypeSample) {
- A_last_OriginTime = header.start+header.length;
- // 加上节目开始的时间
- header.start += programStartTime;
- //assert(header.start+1*10000000 >= (isAudio?A_lastSampleTime:V_lastSampleTime));
- //assert(header.bDiscontinuity == 0);
- header.bDiscontinuity = 0;
- // 记录最近一个Sample的时间
- if(bAudio)
- A_lastSampleTime = header.start;
- else
- V_lastSampleTime = header.start;
- comm->logFile.StatusOut("%s Sample Time %I64d(%I64d) at Block %d", bAudio?"Audio":"Video", header.start,
- header.start - programStartTime, bAudio?A_currBlockID-1:V_currBlockID-1);
- }
- return PRT_OK;
- }
- // 存储Block,在存储之前检查此Block及其后面的一个Block是否正确
- P2P_RETURN_TYPE LiveResource::PutBlock(UINT blockID, UINT blockSize, PBYTE data) {
- if(!bInited) // not started
- return PRT_NOT_INIT;
- CriticalSection::Owner lock(dataLocker);
- assert(mediaArray.FindBlock(blockID));
- P2P_RETURN_TYPE ret = PRT_OK;
- UINT unfinishedSize = 0;
- UINT tmpSize = 0;
- // 1. 读取blockID-1的数据,以便检查blockID块的数据是否正确
- ret = GetBlock(blockID-1, tmpSize, tmpBlockData);
- if(ret != PRT_OK && ret != PRT_BLOCK_NOTFOUND) {// 如果找到或者没找到此块都是正常的,但是其他返回值就不正常了
- assert(0);
- return ret;
- }
- if(ret != PRT_BLOCK_NOTFOUND) {
- // 2. 获取blockID-1块最后一个Sample,在blockID中的剩余长度
- if(!GetUnfinishedSampleSize(tmpBlockData, unfinishedSize)) {
- DelBlock(blockID-1); // 删除错误的blockID-1块
- }
- else if(unfinishedSize != UINT_MAX) {
- // 3. 根据剩余长度检查blockID块数据是否正确
- UINT sampleOffset = *((UINT*)data + 1);
- // TODO: 由于CaptureServer的一个BUG,这里作一个修正,随着所有CaptureServer的更新,这里可以去除。 2005.04.18
- if(sampleOffset == BLOCK_SIZE)
- sampleOffset = UINT_MAX;
- if(sampleOffset != unfinishedSize+sizeof(UINT)*2) {
- if(sampleOffset == UINT_MAX && unfinishedSize > BLOCK_SIZE) {
- ; // blockID块被完全跨越,数据应该是正确的
- }
- else if(!IsFirstBlockOfNewProgram(data)) {
- assert(0);
- return PRT_BAD_BLOCK; // 不是新节目,blockID块数据错误,直接错误
- }
- }
- }
- // 4. 读取blockID+1块
- ret = GetBlock(blockID+1, tmpSize, tmpBlockData);
- if(ret != PRT_OK && ret != PRT_BLOCK_NOTFOUND)// 如果找到或者没找到此块都是正常的,但是其他返回值就不正常了
- return ret;
- if(ret != PRT_BLOCK_NOTFOUND) {
- // 5. 获取blockID块最后一个Sample,在blockID+1中的剩余长度
- if(!GetUnfinishedSampleSize(data, unfinishedSize))
- return PRT_OK; // blockID块数据错误,直接返回
- else if(unfinishedSize != UINT_MAX) {
- // 6. 根据剩余长度检查blockID+1块数据是否正确
- UINT sampleOffset = *((UINT*)tmpBlockData + 1);
- // TODO: 由于CaptureServer的一个BUG,这里作一个修正,随着所有CaptureServer的更新,这里可以去除。 2005.04.18
- if(sampleOffset == BLOCK_SIZE)
- sampleOffset = UINT_MAX;
- if(sampleOffset != unfinishedSize+sizeof(UINT)*2) {
- if(sampleOffset == UINT_MAX && unfinishedSize > BLOCK_SIZE) {
- ; // blockID+1块被完全跨越,数据应该是正确的
- }
- else if(!IsFirstBlockOfNewProgram(tmpBlockData)) {
- assert(0);
- DelBlock(blockID+1); // 删除错误的blockID+1块, 没有记录此块来自哪个NP
- }
- }
- }
- }
- }
- // 数据正确,存储此Block
- return BaseResource::PutBlock(blockID, blockSize, data);
- }
- // 获取此Block末尾一个Sample被截断后,在下一个Block所残留的长度,返回值表示此Block是否数据正确
- bool LiveResource::GetUnfinishedSampleSize(PBYTE& blockData, UINT& unfinishedSize) {
- UINT sampleOffset = *((UINT*)blockData + 1);
- if(sampleOffset == UINT_MAX) {
- unfinishedSize = UINT_MAX;
- return true; // 没法检查,因为sample跨越了整个block,放过这种情况吧
- }
- else if(sampleOffset < sizeof(UINT)*2 || sampleOffset > BLOCK_SIZE) {
- assert(0);
- return false; // 数据错误
- }
- SampleHeader* header = (SampleHeader*)(blockData+sampleOffset);
- while(1) {
- if(sampleOffset+sizeof(UINT) > BLOCK_SIZE) {
- // SampleHeader中的Size尚未读全,没法确定残留的长度,放过这种情况
- unfinishedSize = UINT_MAX;
- return true;
- }
- else if(sampleOffset + header->size >= BLOCK_SIZE) {
- unfinishedSize = sampleOffset + header->size - BLOCK_SIZE; // 这就是残留的长度
- if(unfinishedSize > 1000000)
- assert(0);
- return true;
- }
- sampleOffset += header->size;
- header = (SampleHeader*)(blockData+sampleOffset);
- }
- assert(0);
- return false;
- }
- // 检查此Block是否新节目的第一块
- bool LiveResource::IsFirstBlockOfNewProgram(PBYTE& blockData) {
- UINT sampleOffset = *((UINT*)blockData + 1);
- if(sampleOffset == sizeof(UINT)*2) {
- SampleHeader* header = (SampleHeader*)(blockData+sizeof(UINT)*2);
- // 新节目的第一个Sample格式特殊,具体值如下判断
- if(header->length == 0xffffffff && header->start == 0xffffffffffffffff && header->size == sizeof(SampleHeader))
- return true;
- }
- return false;
- }
- UINT16 LiveResource::GetBufferCount() {
- if(totalBufferCount >= 0xffff)
- return 0xffff;
- return static_cast<UINT16>(totalBufferCount);
- }
- UINT16 LiveResource::GetBufferTime() {
- if(totalBufferTime/1000 >= 0xffff)
- return 0xffff;
- return static_cast<UINT16>(totalBufferTime/1000);
- }
- UINT16 LiveResource::GetBufferingTime() {
- // 如果正在缓冲的过程中,那么把到目前为止的时间也要计算上
- DWORD lastGetSampleFailedTime = A_lastGetSampleFailedTime;
- if(lastGetSampleFailedTime == 0)
- lastGetSampleFailedTime = V_lastGetSampleFailedTime;
- if(lastGetSampleFailedTime != 0) {
- UINT bufTime = timeGetTime()-lastGetSampleFailedTime;
- if(bufTime/1000 >= 0xffff)
- return 0xffff;
- return static_cast<UINT16>(bufTime/1000);
- }
- return 0;
- }
- void LiveResource::SetSPUpdate(const SPUpdate& update, BYTE sum) {
- #ifdef _DEBUG
- // TODO: 测试使用,正式版本一定要去掉
- //spUpdate.minBlockID = spUpdate.maxBlockID = 0;
- #endif
- // 是否尚未收到过SPUpdate
- bool bNoFirstSPUpdate = (spUpdate.minBlockID == 0 && spUpdate.maxBlockID == 0);
- spUpdate = update;
- spUpdateSum = sum;
- // 是否需要重新设置播放位置
- bool bNeedResetPlayingBlock = bNoFirstSPUpdate;
- // 如果播放位置比SP拥有的最小Block还小,就自动调整播放位置
- if(GetPlayingBlock() < spUpdate.minBlockID)
- bNeedResetPlayingBlock = true;
- // 从TIME_BEGIN_PLAY秒钟前的位置开始下载播放
- if(bNeedResetPlayingBlock) {
- const float SECPERBLOCK = bitRate*1024/BLOCK_SIZE; // 每块包含的大致时间长度
- const UINT BLOCK_BEFORE = static_cast<UINT>(TIME_BEGIN_PLAY*SECPERBLOCK); // 提前的块数
- if(spUpdate.maxBlockID >= spUpdate.minBlockID+BLOCK_BEFORE)
- SetPlayingBlock(spUpdate.maxBlockID-BLOCK_BEFORE);
- else
- SetPlayingBlock(spUpdate.minBlockID);
- }
- }
- BOOL LiveResource::SeekToTime(LONGLONG& targetTime) {
- comm->logFile.StatusOut("Begin Seeking......to %ds %dms", targetTime/10000000, targetTime/10000);
- if(!bInited)
- return FALSE;
- if(targetTime == 0) // reset to begin. do nothing.
- return TRUE;
- if((spUpdate.maxKeySample > spUpdate.minKeySample) &&
- (targetTime >= spUpdate.minKeySample) && (targetTime <= spUpdate.maxKeySample) &&
- spUpdate.maxBlockID > spUpdate.minBlockID)
- {
- double temp = ((double)(targetTime-spUpdate.minKeySample))/(spUpdate.maxKeySample-spUpdate.minKeySample);
- UINT targetBlockID = static_cast<UINT>(temp*(spUpdate.maxBlockID-spUpdate.minBlockID))+spUpdate.minBlockID;
- SetPlayingBlock(targetBlockID);
- }
- else {
- comm->logFile.StatusOut("Bad seeking position!");
- return FALSE;
- }
- return TRUE;
- }
- // 添加一个区间对应的媒体类型
- void LiveResource::AddMediaInterval(const MediaInterval& mi) {
- comm->logFile.StatusOut("Got MediaType of [%d, %d).", mi.start, mi.start+mi.size);
- // 是否发生了直播改变编码格式
- bool bLiveChangeMediaData = false;
- if(!mediaArray.AddInterval(mi, &bLiveChangeMediaData)) {
- assert(0);
- return;
- }
- if(bLiveChangeMediaData) {
- // 清除NP连接发送媒体类型区间的记录
- comm->p2pMgr.ClearSentMediaArray();
- // 记录不再向上层提交的媒体类型
- MediaInterval temp;
- if(A_sentArray.FindBlock(A_currBlockID)) {
- if(mediaArray.GetInterval(A_currBlockID, temp)) {
- A_sentArray.Clear();
- A_sentArray.AddInterval(temp);
- }
- }
- if(V_sentArray.FindBlock(V_currBlockID)) {
- if(mediaArray.GetInterval(V_currBlockID, temp)) {
- V_sentArray.Clear();
- V_sentArray.AddInterval(temp);
- }
- }
- }
- }
- // 获取一个Block所在区间的媒体类型
- bool LiveResource::GetMediaInterval(const UINT blockID, MediaInterval& mi) {
- return mediaArray.GetInterval(blockID, mi);
- }
- BOOL LiveResource::SetPlayingBlock(UINT blockID) {
- if(blockID == UINT_MAX)
- return FALSE;
- CriticalSection::Owner lock(dataLocker);
- // 设置开始播放的位置
- A_currBlockID = V_currBlockID = blockID;
- A_leftDataInCurrBlock = V_leftDataInCurrBlock = 0;
- comm->logFile.StatusOut("SetPlayingBlock %d. spupdate.maxblockID %d", blockID, spUpdate.maxBlockID);
- return TRUE;
- }
- // 对于直播, 取得视频音频中比较大(小)的那个BlockID, 当然,如果是单音频或者单视频的,就取得相应的BlockID
- UINT LiveResource::GetPlayingBlock(bool max) {
- if(V_currBlockID == UINT_MAX)
- return A_currBlockID;
- if(A_currBlockID == UINT_MAX)
- return V_currBlockID;
- if(max)
- return max(V_currBlockID, A_currBlockID);
- return min(V_currBlockID, A_currBlockID);
- };
- int LiveResource::GetBufferPercent() {
- // 要保证blocks4Play不等于0,否则此处一定返回100
- if(blocks4Play == 0)
- return 100;
- UINT nextBlock = GetPlayingBlock();
- return min(100, allIntervals.GetCountInInterval(nextBlock, blocks4Play)*100/blocks4Play);
- }
- bool LiveResource::EnlargeBuffer() {
- totalBufferCount++;
- DWORD lastGetSampleFailedTime = A_lastGetSampleFailedTime;
- if(lastGetSampleFailedTime == 0)
- lastGetSampleFailedTime = V_lastGetSampleFailedTime;
- if(lastGetSampleFailedTime != 0)
- totalBufferTime += (timeGetTime() - lastGetSampleFailedTime);
- if(blocks4Play >= static_cast<UINT>(180*bitRate*1024/BLOCK_SIZE)) {
- comm->logFile.StatusOut("Delay more than 3 minutes, do not add.");
- return false;
- }
- comm->logFile.StatusOut("live Pause! Add 50%% time for buffer.");
- blocks4Play = static_cast<UINT>(blocks4Play*1.5f);
- return true;
- }
- void LiveResource::PrintStatus() {
- 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.",
- A_currBlockID, V_currBlockID,
- allIntervals.GetContinousCount(GetPlayingBlock()),
- allIntervals.GetCountInInterval(GetPlayingBlock(), UINT_MAX),
- GetMinBlockID(), GetMaxBlockID(),
- spUpdate.minBlockID, spUpdate.maxBlockID,
- GetBufferPercent(), GetBufferCount(),
- GetBufferTime(), GetBufferingTime());
- }
- void LiveResource::SetDefaultCP() {
- // 直播的默认CP地址就是和SP相同的IP
- if(spIPList) {
- PeerInfoWithAddr nAddr;
- nAddr.outerIP.sin_addr.s_addr = spIPList[0].sin_addr.s_addr;
- nAddr.subnetIP.sin_addr.s_addr = 0xffffffff;
- nAddr.subnetIP.sin_port = htons(CP4NP_PORT);
- nAddr.isCachePeer = true;
- nAddr.layer = 0;
- comm->p2pMgr.AddPeerInfo(nAddr);
- comm->logFile.StatusOut("Choose Default CP %s.", comm->p2pMgr.FormatIPAddress(nAddr));
- }
- };
- // 获取节目名字
- string LiveResource::GetProgramName() {
- MediaInterval mInterval;
- if(!mediaArray.GetInterval(GetPlayingBlock(), mInterval))
- return "";
- if(!mInterval.pname || !mInterval.pnamesize)
- return "";
- string temp = mInterval.pname;
- return temp;
- }
- // 获取节目时间长度
- UINT32 LiveResource::GetProgramTimeInSeconds() {
- MediaInterval mInterval;
- if(!mediaArray.GetInterval(GetPlayingBlock(), mInterval))
- return 0;
- return mInterval.progtime;
- }
- // 获取频道名字
- string LiveResource::GetChannelName() {
- MediaInterval mInterval;
- if(!mediaArray.GetInterval(GetPlayingBlock(), mInterval))
- return "";
- if(!mInterval.cname || !mInterval.cnamesize)
- return "";
- string temp = mInterval.cname;
- return temp;
- }
- }