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

📄 chunkres.cpp

📁 著名的 helix realplayer 基于手机 symbian 系统的 播放器全套源代码
💻 CPP
📖 第 1 页 / 共 3 页
字号:
//		HX_RESULT
//		Possible errors include: TBD.
//
HX_RESULT CChunkyRes::GetData(ULONG32 offset, char* buf, ULONG32 count, ULONG32* actual)
{
	HX_RESULT theErr = HXR_OK;
	int ndx;

	ULONG32 ulFirstChunk = offset/DEF_CHUNKYRES_CHUNK_SIZE;
	ULONG32 ulLastChunk  = (offset+count)/DEF_CHUNKYRES_CHUNK_SIZE;

	HX_ASSERT(ulFirstChunk < INT_MAX);
	HX_ASSERT(ulLastChunk < INT_MAX);

	int		nFirstChunk  = (int)ulFirstChunk;
	int		nLastChunk   = (int)ulLastChunk;

	HX_ASSERT(m_Chunks.GetSize() >= nLastChunk+1);

	ULONG32 chunkOffset = offset - (ulFirstChunk*DEF_CHUNKYRES_CHUNK_SIZE);
	ULONG32 chunkCount  = count;
	ULONG32 baseOffset  = 0;

	*actual = 0;	// -fst
	for (ndx = nFirstChunk; (ndx <= nLastChunk) && chunkCount; ndx++)
	{
		CChunkyResChunk* pChunk = (CChunkyResChunk*)m_Chunks[ndx];

		if (!pChunk)
		{
		    // with random access, it's feasible that there's a null chunk.
		    
		    theErr = HXR_CHUNK_MISSING;
		    goto exit;
		}
		
		HX_ASSERT_VALID_PTR(pChunk);

		ULONG32 chunkActual = 0;

		// Actually get the data from the chunk!
		ULONG32 chunkAmount = min(DEF_CHUNKYRES_CHUNK_SIZE-chunkOffset,chunkCount);
		theErr = pChunk->GetData(chunkOffset,buf+baseOffset,chunkAmount,&chunkActual);
		if (theErr != HXR_OK)
		{
			goto exit;
		}

		// What?!?!
		HX_ASSERT(chunkActual == chunkAmount);

		*actual += chunkActual;		// -fst

		// reduce the chunk count...
		chunkCount -= chunkAmount;
		baseOffset += chunkAmount;

		// only the first chunk has an offset!
		chunkOffset = 0;
	}

	// Remember how many bytes have been served to the user,
	// in case they want us to discard used data
	m_ulUsedBytes = offset + *actual;

	// Discard chunks that have been fully served to the user
	if (m_bDiscardUsedData)
	{
		nLastChunk = (int)(m_ulUsedBytes/DEF_CHUNKYRES_CHUNK_SIZE);
		for (ndx = m_ulFirstChunkIdx; ndx < nLastChunk - 1; ndx++)
		{
			CChunkyResChunk* pChunk = (CChunkyResChunk*)m_Chunks[ndx];
			HX_ASSERT_VALID_PTR(pChunk);

			UINT32 ulTempOffset = pChunk->GetTempFileOffset();
			pChunk->DiscardDiskData();

			// Increment the first valid chunk index
			m_ulFirstChunkIdx++;

			if (ulTempOffset)
			{
			    // Add the disk space to the free space list
			    m_FreeDiskOffsets.AddHead((void*)ulTempOffset);
			}
		}
	}

exit:

	return theErr;
}

HX_RESULT 
CChunkyRes::GetContiguousDataPointer(ULONG32 offset, char*& buf, ULONG32 count)
{
    HX_RESULT theErr = HXR_OK;
    HX_ASSERT(m_bDiscardUsedData == FALSE && m_bDisableDiskIO == FALSE);

    ULONG32 ulFirstChunk = offset/DEF_CHUNKYRES_CHUNK_SIZE;
    ULONG32 ulLastChunk  = (offset+count)/DEF_CHUNKYRES_CHUNK_SIZE;

    HX_ASSERT(ulFirstChunk < INT_MAX);
    HX_ASSERT(ulLastChunk < INT_MAX);

    // if the required data length spans two chunks, we cannot have 
    // contiguous memory
    if (ulFirstChunk != ulLastChunk)
    {
	return HXR_FAIL;
    }

    int nFirstChunk  = (int)ulFirstChunk;
    if (m_Chunks.GetSize() < nFirstChunk+1)
    {
	m_Chunks.SetSize(nFirstChunk+1);
    }
    
    CChunkyResChunk* pChunk = (CChunkyResChunk*)m_Chunks[nFirstChunk];
    if (!pChunk)
    {
	pChunk = new CChunkyResChunk(this);
	if (m_bDisableDiskIO)
	{
	    pChunk->DisableDiskIO();
	}
	m_Chunks[nFirstChunk] = pChunk;
    }

    HX_ASSERT(m_Chunks.GetSize() >= nFirstChunk+1);
    HX_ASSERT_VALID_PTR(pChunk);

    ULONG32 chunkOffset = offset - (ulFirstChunk*DEF_CHUNKYRES_CHUNK_SIZE);
    // Actually get the data from the chunk!
    ULONG32 chunkAmount = min(DEF_CHUNKYRES_CHUNK_SIZE-chunkOffset, count);

    theErr = pChunk->GetContiguousDataPointer(chunkOffset,buf,chunkAmount);
    return theErr;
}

/////////////////////////////////////////////////////////////////////////////
//
//	Method:
//
//		CChunkyRes::SetData()
//
//	Purpose:
//
//		Sets a block of data in a resource.
//
//	Parameters:
//
//		ULONG32 offset
//		const char* buf
//		ULONG32 count
//
//	Return:
//
//		HX_RESULT
//		Possible errors include: TBD.
//
HX_RESULT CChunkyRes::SetData(ULONG32 offset, const char* buf, ULONG32 count)
{
	HX_RESULT theErr = HXR_OK;

	ULONG32 ulFirstChunk = offset/DEF_CHUNKYRES_CHUNK_SIZE;
	ULONG32 ulLastChunk  = (offset+count)/DEF_CHUNKYRES_CHUNK_SIZE;

	HX_ASSERT(ulFirstChunk < INT_MAX);
	HX_ASSERT(ulLastChunk < INT_MAX);

	int		nFirstChunk  = (int)ulFirstChunk;
	int		nLastChunk   = (int)ulLastChunk;

	if (m_Chunks.GetSize() < nLastChunk+1)
	{
		m_Chunks.SetSize(nLastChunk+1);
	}

	ULONG32 chunkOffset = offset - (ulFirstChunk*DEF_CHUNKYRES_CHUNK_SIZE);
	ULONG32 chunkCount  = count;
	ULONG32 baseOffset  = 0;

	for (int ndx = nFirstChunk; ndx <= nLastChunk; ndx++)
	{
		CChunkyResChunk* pChunk = (CChunkyResChunk*)m_Chunks[ndx];

		if (!pChunk)
		{
			pChunk = new CChunkyResChunk(this);
			if (m_bDisableDiskIO)
			{
			    pChunk->DisableDiskIO();
			}
			m_Chunks[ndx] = pChunk;
		}

		// Actually set the data for the chunk!
		theErr = pChunk->SetData(chunkOffset,buf+baseOffset,min(DEF_CHUNKYRES_CHUNK_SIZE-chunkOffset,chunkCount));
		if (theErr != HXR_OK)
		{
			goto exit;
		}

		// reduce the chunk count...
		chunkCount -= (DEF_CHUNKYRES_CHUNK_SIZE-chunkOffset);
		baseOffset += (DEF_CHUNKYRES_CHUNK_SIZE-chunkOffset);

		// only the first chunk has an offset!
		chunkOffset = 0;
	}

exit:

	return theErr;
}

void CChunkyRes::TrimDownMemoryMRU()
{
	// If we have just reduced our allowed memory usage, then
	// discard the least recently used chunks till we are under
	// the ne threshold...
	if (m_CurMemUsage > m_MemUsageThreshold)
	{
		while (!m_ChunksMemoryMRU->IsEmpty() && (m_CurMemUsage > m_MemUsageThreshold))
		{
			// Get the least recently used chunk.
			CChunkyResChunk* pChunk = (CChunkyResChunk*)m_ChunksMemoryMRU->GetTail();
			HX_ASSERT_VALID_PTR(pChunk);

			// Discount its usage.
			m_CurMemUsage -= pChunk->GetSize();

			// Spill this chunk to disk...
			pChunk->SpillToDisk();

			// Remove the chunk from the end of the Memory MRU
			m_ChunksMemoryMRU->RemoveTail();

			// And add the chunk to the front of the Disk MRU
			m_ChunksDiskMRU->AddHead(pChunk);
		}

		// How can this be?!?! Did you really mean to set the memory usage such
		// that there are no chunks in memory?!?
		HX_ASSERT(!m_ChunksMemoryMRU->IsEmpty());
	}
}

/////////////////////////////////////////////////////////////////////////////
//
//	Method:
//
//		CChunkyResChunk::SetMemUsageThreshold()
//
//	Purpose:
//
//		Sets the memory usage threshold for the chunky resource chunks.
//		If if chunk sizes amount to more than the threshold, then the
//		least recently used ones will be spilled to disk.
//
//	Parameters:
//
//		ULONG32 memUsage
//		Memory usage in bytes which will be allowed for all chunks before
//		least recently used chunks will be spilled to disk.
//
//	Return:
//
//		None.
//
void CChunkyRes::SetMemUsageThreshold(ULONG32 memUsage)
{
	m_MemUsageThreshold = memUsage;
	TrimDownMemoryMRU();
}

/////////////////////////////////////////////////////////////////////////////
//
//	Method:
//
//		CChunkyRes::CChunkyRes()
//
//	Purpose:
//
//		Constructor for a chunky resource.
//
//	Parameters:
//
//		None.
//
//	Return:
//
//		N/A
//
CChunkyRes::CChunkyRes()
	: m_Chunks()
	, m_strTempFileName()
	, m_ulNextTempFileChunk(DEF_START_CHUNK_OFFSET)
	, m_bHasBeenOpened(FALSE)
	, m_bDisableDiskIO(FALSE)
	, m_bDiscardUsedData(FALSE)
	, m_ulFirstChunkIdx(0)
	, m_ulUsedBytes(0)
	, m_pMutex(0)
	, m_MemUsageThreshold(DEF_CHUNKYRES_MEM_THRESHOLD)
	, m_CurMemUsage(0)
	, m_ChunksMemoryMRU(NULL)
	, m_ChunksDiskMRU(NULL)
	, m_ChunkSize(DEF_CHUNKYRES_CHUNK_SIZE)
{
#if defined(THREADS_SUPPORTED)
    HXMutex::MakeMutex(m_pMutex);
#else
    HXMutex::MakeStubMutex(m_pMutex);
#endif
    HX_ASSERT(m_pMutex);

    m_ChunksMemoryMRU = new CHXSimpleList;
    m_ChunksDiskMRU = new CHXSimpleList;

    HX_ASSERT(m_ChunksMemoryMRU);
    HX_ASSERT(m_ChunksDiskMRU);
}

/////////////////////////////////////////////////////////////////////////////
//
//	Method:
//
//		CChunkyRes::~CChunkyRes()
//
//	Purpose:
//
//		Destructor for a chunky resource.
//
//	Parameters:
//
//		None.
//
//	Return:
//
//		N/A
//
CChunkyRes::~CChunkyRes()
{
	// If we are getting rid of the resource, then
	// we should discard all of the chunks...
	for (int ndx = 0; ndx < m_Chunks.GetSize(); ndx++)
	{
		CChunkyResChunk* pChunk = (CChunkyResChunk*)m_Chunks[ndx];
		if (pChunk)
		{
			delete pChunk;
		}
	}
	HX_RESULT theErr = DiscardDiskData();
	HX_ASSERT(theErr == HXR_OK);

	if(m_ChunksMemoryMRU)
	{
	    HX_ASSERT(m_ChunksMemoryMRU->GetCount() == 0);
	    delete m_ChunksMemoryMRU;
	    m_ChunksMemoryMRU = NULL;
	}
	
	if(m_ChunksDiskMRU)
	{
	    HX_ASSERT(m_ChunksDiskMRU->GetCount() == 0);
	    delete m_ChunksDiskMRU;
	    m_ChunksDiskMRU = NULL;
	}

	HX_DELETE(m_pMutex);
}


/////////////////////////////////////////////////////////////////////////////
//
//	Method:
//
//		CChunkyResChunk::MakeSureChunkIsInMemory()
//
//	Purpose:
//
//		Get a portion of the data for a chunk.
//
//	Parameters:
//
//		ULONG32 offset
//		char* buf
//		ULONG32 count
//		ULONG32* actual
//
//	Return:
//
//		HX_RESULT
//		Possible errors include: TBD.
//
HX_RESULT CChunkyResChunk::MakeSureChunkIsInMemory()
{
	HX_RESULT theErr = HXR_OK;

	// If we don't have a chunk pointer, then we aren't in
	// memory...
	if (!m_pChunkData)
	{
		// Find ourselves in the MRU list for Disk chunks...
		LISTPOSITION pos = m_pChunkRes->m_ChunksDiskMRU->Find(this);

		// If were found in the disk MRU list, then we have
		// some work to do...
		if (pos)
		{
			// First, remove ourselves from the disk list...
			m_pChunkRes->m_ChunksDiskMRU->RemoveAt(pos);

			// Load from disk...
			theErr = LoadFromDisk();
			if (theErr != HXR_OK)
			{
				goto exit;
			}
		}
		else
		{
			#ifdef _DEBUG
			{
				// We shouldn't find ourselves in the MRU list
				// for memory chunks... but we want to check!
				LISTPOSITION pos = m_pChunkRes->m_ChunksMemoryMRU->Find(this);

				// We shouldn't be in this list!!!!
				HX_ASSERT(pos == NULL);
			}
			#endif // end _DEBUG section

			m_pChunkData = new UCHAR[m_pChunkRes->m_ChunkSize];

			HX_ASSERT(GetValidLength() == 0);
		}

		// Add to the front of the Memory list...
		m_pChunkRes->m_ChunksMemoryMRU->AddHead(this);

		m_pChunkRes->m_CurMemUsage += GetSize();

		// Make sure we don't have to much info in memory...
		if (!m_bDisableDiskIO)
		{
		    m_pChunkRes->TrimDownMemoryMRU();
		    HX_ASSERT(m_pChunkData);
		}
	}
	// If we are already in memory, then make sure we are at the
	// top of the Memory MRU list!!!
	else
	{
		// We should find ourselves in the MRU list
		// for memory chunks... but we want to check!
		LISTPOSITION pos = m_pChunkRes->m_ChunksMemoryMRU->Find(this);

		// XXXNH: If we aren't in this list it means we were paged out,
		// so we only need to put ourselves at the top of the MRU list
		if (pos)
		{
		    // First, remove ourselves from wherever we are in the
		    // Memory MRU list...
		    m_pChunkRes->m_ChunksMemoryMRU->RemoveAt(pos);
		}

		// And add ourselves to the top of the list!
		m_pChunkRes->m_ChunksMemoryMRU->AddHead(this);
	}

exit:

	return theErr;
}

/////////////////////////////////////////////////////////////////////////////
//
//	Method:
//
//		CChunkyResChunk::GetValidLength()
//
//	Purpose:
//
//		Determines how much of a chunk is valid
//
//	Parameters:
//
//		ULONG32 offset
//
//	Return:
//
//		HX_RESULT
//		Possible errors include: TBD.
//
ULONG32 CChunkyResChunk::GetValidLength(ULONG32 offset /* = 0 */) const
{
    
    HX_ASSERT(offset < GetSize());
    
    ULONG32 ulValidLength = 0;
    
	LISTPOSITION rangePos = m_ValidRanges.GetHeadPosition();
	
	if (rangePos)
	{
		do
		{
			ValidRange* pRange = (ValidRange*)m_ValidRanges.GetNext(rangePos);

			HX_ASSERT(pRange);

			// see if the offset points into this particular range

			if (offset >= pRange->offset
				&& offset <= pRange->offset + pRange->length)
			{
			    ulValidLength = pRange->offset + pRange->length - offset;
			}
		}
		while (rangePos);
	}
	
    return ulValidLength;
}

/////////////////////////////////////////////////////////////////////////////
//
//	Method:
//
//		CChunkyResChunk::GetData()
//
//	Purpose:
//
//		Get a portion of the data for a chunk.
//
//	Parameters:
//
//		ULONG32 offset
//		char* buf
//		ULONG32 count
//		ULONG32* actual
//
//	Return:
//
//		HX_RESULT
//		Possible errors include: TBD.
//
HX_RESULT CChunkyResChunk::GetData(ULONG32 offset, char* buf, ULONG32 count, ULONG32* actual)
{
	HX_RESULT theErr;

	if(!count)
	{
		*actual = count;
		return HXR_OK;
	}

	// We should have a non-zero valid size
	if (!GetValidLength(offset))
	{
		// This chunk must have been discarded
		theErr = HXR_CHUNK_MISSING;
		goto exit;
	}

	// Make sure this chunk is in memory!
	theErr = MakeSureChunkIsInMemory();

	if (theErr != HXR_OK)
	{
		goto exit;
	}

	// You can't read more than there is room in this chunk.
	// CChunkyRes should prevent this case...
	HX_ASSERT(offset+count <= GetSize());

	// The call to MakeSureChunkIsInMemory() should have handled this!
	HX_ASSERT_VALID_PTR(m_pChunkData);

	*actual = min(count,GetValidLength(offset));

	HX_ASSERT(*actual < UINT_MAX);

	memcpy(buf,m_pChunkData+offset,(int)(*actual)); /* Flawfinder: ignore */

exit:

	return theErr;
}

HX_RESULT 
CChunkyResChunk::GetContiguousDataPointer(ULONG32 offset, char*& buf, ULONG32 count)
{
    HX_RESULT theErr = HXR_OK;

    if(!count)
    {
	theErr = HXR_FAIL;
	goto exit;
    }

    // First, make sure this chunk is in memory!
    theErr = MakeSureChunkIsInMemory();
    if (theErr != HXR_OK)
    {
	goto exit;
    }

    // You can't write more than there is room in this chunk.
    // CChunkyRes should prevent this case...
    HX_ASSERT(offset+count <= GetSize());

    // Currently, you must write to chunks in order from the
    // start of the chunk first. Random access may come in the
    // future...
    HX_ASSERT(GetValidLength(offset) > 0); // needed still at all?

    // The call to MakeSureChunkIsInMemory() should have handled this!
    HX_ASSERT_VALID_PTR(m_pChunkData);

    AddValidRange(offset, count);
    
    HX_ASSERT(count < UINT_MAX);

    buf = (char*) (m_pChunkData+offset);

    m_bModified = TRUE;

exit:

    return theErr;
}

/////////////////////////////////////////////////////////////////////////////
//
//	Method:
//
//		CChunkyResChunk::AddValidRange()
//
//	Purpose:
//
//		Mark a part of this CChunkyResChunk as valid
//		Called from SetData.
//
//	Parameters:
//
//		ULONG32 offset
//		ULONG32 length
//		BOOL	bValid
//
//	Return:
//
//		HX_RESULT
//		Possible errors include: TBD.
//
HX_RESULT CChunkyResChunk::AddValidRange(ULONG32 offset, ULONG32 length, BOOL bValid /* = TRUE */)
{
	HX_RESULT theErr = HXR_OK;
	
    int nCount = m_ValidRanges.GetCount();
    LISTPOSITION pos = m_ValidRanges.GetHeadPosition();
	

⌨️ 快捷键说明

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