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

📄 zzlfilereader.cpp

📁 mysee网络直播源代码Mysee Lite是Mysee独立研发的网络视频流媒体播放系统。在应有了P2P技术和一系列先进流媒体技术之后
💻 CPP
字号:
#include "stdafx.h"
#include "ZZLFileReader.h"

#ifndef SAFE_ARRAYDELETE
#define SAFE_ARRAYDELETE( x )  \
	if( NULL != x )        \
{                      \
	delete [] x;       \
	x = NULL;          \
}
#endif

ZZLFileReader::ZZLFileReader() :
			   FILE_VERSION(1.0f),
			   MAX_HEADER_SIZE(1024),
			   LIMIT_DOWN_SPEED(150.0f),
               m_VideoEndTime(0),
               m_AudioEndTime(0)
{
	m_hFile           = INVALID_HANDLE_VALUE;
	m_iHeaderSize     = 0;
	m_iFileSize       = 0;
	m_iDownloadedSize = 0;
	//
	m_pAudioFormat      = NULL;
	m_pVideoFormat      = NULL;
	m_startTime       = 0; 
	m_endTime         = 0;
	A_currBlockID     = 0;
	V_currBlockID     = 0;
	
	m_hDownThread     = NULL;
	m_isStopped       = FALSE;
	//
	A_iLeftDataInCurrBlock = 0;
	V_iLeftDataInCurrBlock = 0;
}

ZZLFileReader::~ZZLFileReader(void) 
{
	m_iHeaderSize = 0;
	m_isStopped   = TRUE; // stop thread

	if (INVALID_HANDLE_VALUE != m_hFile )
	{
		CloseHandle(m_hFile);
		m_hFile = INVALID_HANDLE_VALUE;
	}
	//
	//
	SAFE_ARRAYDELETE(m_pAudioFormat);
	SAFE_ARRAYDELETE(m_pVideoFormat);
}

bool ZZLFileReader::Init(const char* filename)
{
	CAutoLock l(&m_pLock);
	//
	if(!filename)
	{
		ASSERT(FALSE);
		return false;
	}
	//
    if(m_hFile != INVALID_HANDLE_VALUE)
        return true;

	// 打开文件句柄
	m_hFile = CreateFile(filename, GENERIC_READ, 
						FILE_SHARE_READ, NULL, 
						OPEN_EXISTING,  // 本地文件
						FILE_ATTRIBUTE_NORMAL, NULL);
	//
	if(m_hFile == INVALID_HANDLE_VALUE)
	{
		int xxx = GetLastError();
		return false;
	}

	m_iFileSize = GetFileSize(m_hFile, NULL);
	m_iDownloadedSize = m_iFileSize;	// 本地文件!当然数据是全的

		// 本地文件,直接读取文件头
	if(!ReadFileHeader())
	{
		ASSERT(FALSE);
		return false;
	}
	//
	return true;
}

void __stdcall ZZLFileReader::RunHttpDownload(ZZLFileReader* reader)
{
    return;
}

bool ZZLFileReader::ReadFileHeader()
{
	CAutoLock l(&m_pLock);
	
	if(m_iDownloadedSize < MAX_HEADER_SIZE)
	{
		return false;
	}
	//
	if(IsInited())
	{
		return true;
	}
	//
	DWORD readBytes = 0;
	float version;
	// 1. check "ZZLD"
	char fcc[5] = "";
	fcc[4] = 0;
	//
	if(INVALID_SET_FILE_POINTER == SetFilePointer(m_hFile, 0, 0, FILE_BEGIN))
	{
		return false;
	}
	//
	if(!ReadFile(m_hFile, fcc, 4, &readBytes, NULL))
	{
		return false;
	}
	//
	if(readBytes != 4 || stricmp(fcc, "ZZLD") != 0)
	{
		return false;
	}	
	// 2. check file version
	if(!ReadFile(m_hFile, &version, sizeof(version), &readBytes, NULL))
	{
		return false;
	}
	//
	if(readBytes != sizeof(version) || version > FILE_VERSION)
	{
		return false;
	}

	// 3. read video type
	if(!ReadFile(m_hFile, &m_VideoType, sizeof(m_VideoType), &readBytes, NULL))
	{
		return false;
	}
	//
	if(readBytes != sizeof(m_VideoType) && m_VideoType.cbFormat > 1024)
	{
		return false;
	}
	//
	SAFE_ARRAYDELETE(m_pVideoFormat);
	//
	m_pVideoFormat = new BYTE[m_VideoType.cbFormat];
	//
	if(!ReadFile(m_hFile, m_pVideoFormat, m_VideoType.cbFormat, &readBytes, NULL))
	{
		return false;
	}
	//
	if(readBytes != m_VideoType.cbFormat)
	{
		return false;
	}

	// 4. read audio type
	if(!ReadFile(m_hFile, &m_AudioType, sizeof(m_AudioType), &readBytes, NULL))
	{
		return false;
	}
	//
	if(readBytes != sizeof(m_AudioType) && m_AudioType.cbFormat > 1024)
	{
		return false;
	}
	//
	SAFE_ARRAYDELETE(m_pAudioFormat);
	//
	m_pAudioFormat = new BYTE[m_AudioType.cbFormat];
	//
	if(!ReadFile(m_hFile, m_pAudioFormat, m_AudioType.cbFormat, &readBytes, NULL))
	{
		return false;
	}
	//
	if(readBytes != m_AudioType.cbFormat)
	{
		return false;
	}

	// 5. read start time, end time
	time_t temp = 0;
	if(!ReadFile(m_hFile, &temp, sizeof(temp), &readBytes, NULL))
	{
		return false;
	}
	//
	if(readBytes != sizeof(temp))
	{
		return false;
	}
	//
	m_startTime  = temp;
	m_startTime *= 10000000;
	if(!ReadFile(m_hFile, &temp, sizeof(temp), &readBytes, NULL))
	{
		return false;
	}
	//
	if(readBytes != sizeof(temp))
	{
		return false;
	}
	//
	m_endTime  = temp;
	m_endTime *= 10000000;
	//
	if(m_endTime < m_startTime || m_endTime == 0)
	{
		return false;
	}

	m_iHeaderSize = 4 + sizeof(version) + sizeof(m_AudioType) + 
					m_AudioType.cbFormat  + sizeof(m_VideoType) +
					m_VideoType.cbFormat + 
					sizeof(temp) +
					sizeof(temp);
	//
	//m_pFilter->SetBaseRef(m_startTime);
	//
	return true;
}

// 获取媒体类型
int ZZLFileReader::GetMediaType(TVMEDIATYPESECTION& mediatype, BOOL isAudio)
{
	CAutoLock l(&m_pLock);
	//
	if(!IsInited())
	{
		if(!ReadFileHeader())
		{
			return FALSE;
		}
	}
	//
	if(isAudio)
	{
		if(!m_pAudioFormat)
		{
			return FALSE;
		}
		//
		mediatype = m_AudioType;
	}
	else 
	{
		if(!m_pVideoFormat)
		{
			return FALSE;
		}
		//
		mediatype = m_VideoType;
	}
	//
	return TRUE;
}

// 获取媒体数据
int ZZLFileReader::GetMediaData(PBYTE data, BOOL isAudio)
{
	CAutoLock l(&m_pLock);
	//
	if(!data)
	{
		ASSERT(NULL != data);
		return FALSE;
	}
	//
	if(!IsInited()) 
	{
		if(!ReadFileHeader())
		{
			ASSERT(FALSE);
			return FALSE;
		}
	}
	//
	if(isAudio) 
	{
		if(!m_pAudioFormat)
		{
			ASSERT(NULL != m_pAudioFormat);
			return FALSE;
		}
		//
		memcpy(data, m_pAudioFormat, m_AudioType.cbFormat);
	}
	else
	{
		if(!m_pVideoFormat)
		{
			return FALSE;
		}
		//
		memcpy(data, m_pVideoFormat, m_VideoType.cbFormat);
	}
	//
	return TRUE;
}

STDMETHODIMP ZZLFileReader::GetAvailable(LONGLONG& pEarliest,LONGLONG& pLatest)
{
	CAutoLock l(&m_pLock);
	//
	if(!IsInited())
	{
		if(!ReadFileHeader())
		{
			ASSERT(FALSE);
			return S_FALSE;
		}
	}
	//
	pEarliest = 0;
	pLatest   = m_endTime - m_startTime;
	//
	return S_OK;
}

STDMETHODIMP ZZLFileReader::GetDuration(LONGLONG& pDuration)
{
	CAutoLock l(&m_pLock);
	//
	if(!IsInited()) 
	{
		if(!ReadFileHeader())
		{
			ASSERT(FALSE);
			return S_FALSE;
		}
	}
	//
	pDuration = m_endTime - m_startTime;
	//
	return S_OK;
}
//
STDMETHODIMP ZZLFileReader::GetStopPosition(LONGLONG& pStop) 
{
	CAutoLock l(&m_pLock);
	//
	if(!IsInited()) 
	{
		if(!ReadFileHeader())
		{
			ASSERT(FALSE);
			return S_FALSE;
		}
	}
	//
	pStop = m_endTime-m_startTime;

	return S_OK;
}

// Seek到某个时间
bool ZZLFileReader::SeekTo(LONGLONG& seekTime, int pin)
{
	CAutoLock l(&m_pLock);
	if(!IsInited()) 
	{
		if(!ReadFileHeader())
		{
			ASSERT(FALSE);
			return false;
		}
	}
	//
	if(seekTime > m_endTime)
	{
		seekTime = m_endTime;
	}
	//
	if(seekTime <= m_startTime) 
	{
		 seekTime  = m_startTime;
	}
	// TODO: 使用二分查找
	UINT targetBlockID = (UINT)(((double)(seekTime - m_startTime)/(m_endTime - m_startTime)*(m_iFileSize-m_iHeaderSize))/BLOCK_SIZE);
	
	//
    if((pin & 1) == 1)
    {
	    A_currBlockID = targetBlockID;
        A_iLeftDataInCurrBlock = 0;
    }
    if((pin & 2) == 2)
    {
	    V_currBlockID = targetBlockID;
        V_iLeftDataInCurrBlock = 0;
    }
	//
	
	//
	return true;
}

bool ZZLFileReader::SeekVideoTo(LONGLONG& seekTime)
{
    return SeekTo(seekTime, 2);
}

bool ZZLFileReader::SeekAudioTo(LONGLONG& seekTime)
{
    return SeekTo(seekTime, 1);
}

// 获取Sample. 
// m_startTime != _I64_MAX的话,寻找m_startTime之后的第一个Sample,
// 视频Sample的话还要满足是关键帧的条件
P2P_RETURN_TYPE ZZLFileReader::GetSample(SampleHeader& header,	// Sample头
										 PBYTE& pData,			// Sample数据
										 const UINT maxSize,	// Sample的最大值
										 LONGLONG seekTime)		// Seek的目标时间



{
	CAutoLock l(&m_pLock);

	if(!IsInited())
	{
		if(!ReadFileHeader())
			return PRT_NOT_INIT;
	}
	//
	
	if(seekTime != _I64_MAX)
	{
		SeekTo(seekTime);
	}
	//
	bool isAudio = header.bAudioSample;
	
	for(;;)
	{
		for(;;) 
		{
			P2P_RETURN_TYPE ret = LoadSample(header, pData, 0, maxSize, isAudio);
			if(ret < PRT_OK)
				return ret;

			// 节目开始的标志Sample,在ZZL文件中略过,不用处理
			if(header.length == 0xffffffff || header.start == 0xffffffffffffffff)
				continue;

			//
			//if (header.start < m_startTime)
			//	continue;
			// 如果是目标类型,则完成寻找
			if(isAudio == header.bAudioSample)
			{
				if (seekTime != _I64_MAX) //seeking
				{
					// Seek时,获取视频关键帧
					if(!isAudio && header.bSyncPoint)
					{
						m_llSeekTo = header.start;
						break;
					}
				}else
				{
					break;
				}
			}
		}
		
		if (header.start >= m_llSeekTo)
		{
			break;
		}
	}
	//
	//header.start -= m_startTime;//m_llSeekTo;
    if(header.start != -1)
    {
        LONGLONG tmp = header.start + header.length;
        if(isAudio)
        {
	        if(tmp > m_AudioEndTime)
                m_AudioEndTime = tmp;
        }
        else
        {
            if(tmp > m_VideoEndTime)
                m_VideoEndTime = tmp;
        }
    }
    DbgLog((LOG_TRACE, 1, TEXT("Deliver sample, baudio is %d, start at %I64d, length is %d, size is %d"), header.bAudioSample,
        header.start, header.length, header.size));
	//
	return PRT_OK;
}
//
P2P_RETURN_TYPE ZZLFileReader::LoadSample(SampleHeader& header,	// Sample头
								PBYTE& sampleData,		// Sample数据
								UINT sampleOff,			// 已经读取的长度
								const UINT maxSize,		// Sample最大长度
								const bool isAudio)		// 视频还是音频 
{
	UINT& currBlockID = isAudio ? A_currBlockID : V_currBlockID;
	BYTE *currBlock   = isAudio ? A_currBlock   : V_currBlock;
	//
	UINT& leftDataInCurrBlock = isAudio ? A_iLeftDataInCurrBlock : V_iLeftDataInCurrBlock;
	DWORD readBytes = 0;
	//
	UINT  iCurrentPos = m_iHeaderSize + currBlockID*BLOCK_SIZE; 
	//
	while(0 == leftDataInCurrBlock)
	{ // not data in current block, load next
		// 读取当前块数据
        if(iCurrentPos == m_iFileSize)  //文件已经读到头了
        {
            return PRT_ENDOFFILE;
        }

		if(INVALID_SET_FILE_POINTER == SetFilePointer(m_hFile, iCurrentPos,	NULL, FILE_BEGIN))
		{
			ASSERT(FALSE);
			return PRT_SYS;
		}

		if(iCurrentPos + BLOCK_SIZE > m_iFileSize)
		{
			//ASSERT(FALSE);
			return PRT_SYS;				// 超出了文件大小,不正常
		}
		//
		if(iCurrentPos + BLOCK_SIZE > m_iDownloadedSize)
		{
			ASSERT(FALSE);
			return PRT_BLOCK_NOTFOUND;	// 尚未下载到这里呢
		}
		//
		if(!ReadFile(m_hFile, currBlock, BLOCK_SIZE, &readBytes, NULL))
		{
			ASSERT(FALSE);
			return PRT_SYS;
		}
		//
		currBlockID++;
		//
		// 第4~8个字节是first sample offset
		UINT sampleOffset = *((UINT*)currBlock+1);
		// 注意:8是keySampleOffset和sampleOffset占用的空间大小
		if(sampleOffset != UINT_MAX &&
		  (sampleOffset < 8 || sampleOffset > BLOCK_SIZE)) 
		{
			assert(0);
			continue; // 错误的SampleOffset,抛弃当前块
		}

		// 由于CaptureServer的一个BUG,这里作一个修正,随着所有CaptureServer的更新,这里可以去除。 2005.04.18
		if(sampleOffset == BLOCK_SIZE)
		{
			sampleOffset = UINT_MAX;
		}
		//
		if(sampleOff == 0) 
		{ // 开始读取新的Sample
			if(sampleOffset == UINT_MAX)
			{
                iCurrentPos += BLOCK_SIZE;
				continue; // 新的Sample不在当前Block中,继续寻找下一个
			}
			else 
			{
				leftDataInCurrBlock = BLOCK_SIZE-sampleOffset; // 新的Sample位置
			}
		}
		else
		{
			// 继续读取剩余的数据
			leftDataInCurrBlock = BLOCK_SIZE-8; 
			assert(sampleOffset==UINT_MAX || sampleOff < sizeof(SampleHeader) || sampleOffset == 8+header.size-sampleOff);
		}
		//
		assert(leftDataInCurrBlock <= BLOCK_SIZE);
		break;
	}
	//
	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);
		}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);
			}
			//
			leftDataInCurrBlock -= (sizeof(SampleHeader)-sampleOff);
			sampleOff = sizeof(SampleHeader);
		}
	}

	startOff = currBlock+(BLOCK_SIZE - leftDataInCurrBlock); 
	// 读取SampleHeader之外的数据
	if(sampleOff >= sizeof(SampleHeader)) 
	{
		if(leftDataInCurrBlock < header.size-sampleOff)
		{
			// 当前块中剩下的数据不足,继续读取下一块
			memcpy(sampleData+sampleOff-sizeof(SampleHeader), startOff, leftDataInCurrBlock);
			sampleOff += leftDataInCurrBlock;
			leftDataInCurrBlock = 0;
			return LoadSample(header, sampleData, sampleOff, maxSize, isAudio);
		}else
		{
			// 读取到完整的Sample
			memcpy(sampleData+sampleOff-sizeof(SampleHeader), startOff, header.size-sampleOff);
			leftDataInCurrBlock -= (header.size-sampleOff);
		}
	}
	//
	assert(leftDataInCurrBlock <= BLOCK_SIZE);
	return PRT_OK;
}

⌨️ 快捷键说明

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