Exemple #1
0
sboolean MP3Stream_SeekTo( channel_t *ch, float fTimeToSeekTo )
{		
	const float fEpsilon = 0.05f;	// accurate to 1/50 of a second, but plus or minus this gives 1/10 of second

	MP3Stream_Rewind( ch );
	//
	// sanity... :-)
	//
	const float fTrackLengthInSeconds = MP3Stream_GetPlayingTimeInSeconds( &ch->MP3StreamHeader );
	if (fTimeToSeekTo > fTrackLengthInSeconds)
	{
		fTimeToSeekTo = fTrackLengthInSeconds;
	}

	// now do the seek...
	//
	while (1)
	{
		float fPlayingTimeElapsed = MP3Stream_GetPlayingTimeInSeconds( &ch->MP3StreamHeader ) - MP3Stream_GetRemainingTimeInSeconds( &ch->MP3StreamHeader );
		float fAbsTimeDiff = fabs(fTimeToSeekTo - fPlayingTimeElapsed);

		if ( fAbsTimeDiff <= fEpsilon)
			return qtrue;

		// when decoding, use fast-forward until within 3 seconds, then slow-decode (which should init stuff properly?)...
		//
		int iBytesDecodedThisPacket = C_MP3Stream_Decode( &ch->MP3StreamHeader, (fAbsTimeDiff > 3.0f) );	// bFastForwarding
		if (iBytesDecodedThisPacket == 0)
			break;	// EOS		
	}

	return qfalse;
}
Exemple #2
0
// decode one packet of MP3 data only (typical output size is 2304, or 2304*2 for stereo, so input size is less
//
// return is decoded byte count, else 0 for finished
//
int MP3Stream_Decode( LP_MP3STREAM lpMP3Stream, qboolean bDoingMusic )
{
	lpMP3Stream->iCopyOffset = 0;

	if (0)//!bDoingMusic)
	{
		// SOF2: need to make a local buffer up so we can decode the piece we want from a contiguous bitstream rather than
		//	this linklist junk...
		//
		// since MP3 packets are generally 416 or 417 bytes in length it seems reasonable to just find which linked-chunk
		//	the current read offset lies within then grab the next one as well (since they're 2048 bytes) and make one
		//	buffer with just the two concat'd together. Shouldn't be much of a processor hit.
		//
		sndBuffer *pChunk = (sndBuffer *) lpMP3Stream->pbSourceData;	
		//
		// may as well make this static to avoid cut down on stack-validation run-time...
		//
		static byte	byRawBuffer[SND_CHUNK_SIZE_BYTE*2];	// *2 for byte->short	// easily enough to decode one frame of MP3 data, most are 416 or 417 bytes
			
		// fast-forward to the correct chunk...
		//		
		int iBytesToSkipPast = lpMP3Stream->iSourceReadIndex;

		while (iBytesToSkipPast >= SND_CHUNK_SIZE_BYTE) 
		{
			pChunk = pChunk->next;			
			if (!pChunk) 
			{
				// err.... reading off the end of the data stream guys...
				//
				// pChunk = (sndBuffer *) lpMP3Stream->pbSourceData;	// restart
				return 0;	// ... 0 bytes decoded, so will just stop caller-decoder all nice and legal as EOS
			}
			iBytesToSkipPast -= SND_CHUNK_SIZE_BYTE;
		}
		// ok, pChunk is now the 2k or so chunk we're in the middle of...
		//
		int iChunk1BytesToCopy = SND_CHUNK_SIZE_BYTE - iBytesToSkipPast;
		memcpy(byRawBuffer,((byte *)pChunk->sndChunk) + iBytesToSkipPast, iChunk1BytesToCopy);
		//
		// concat next chunk on to this as well...
		//
		pChunk = pChunk->next;
		if (pChunk)
		{
			memcpy(byRawBuffer + iChunk1BytesToCopy, pChunk->sndChunk,	SND_CHUNK_SIZE_BYTE);
		}
		else
		{
			memset(byRawBuffer + iChunk1BytesToCopy, 0,					SND_CHUNK_SIZE_BYTE);
		}


		// now we need to backup some struct fields, fake 'em, do the lo-level call, then restore 'em...
		//
		byte *pbSourceData_Old	= lpMP3Stream->pbSourceData;
		int iSourceReadIndex_Old= lpMP3Stream->iSourceReadIndex;

		lpMP3Stream->pbSourceData	= &byRawBuffer[0];
		lpMP3Stream->iSourceReadIndex= 0;	// since this is zero, not the buffer offset within a chunk, we can play tricks further down when restoring

		unsigned int uiBytesDecoded = C_MP3Stream_Decode( lpMP3Stream );

		lpMP3Stream->iSourceReadIndex += iSourceReadIndex_Old;	// note '+=' rather than '=', to take account of movement.
		lpMP3Stream->pbSourceData	   = pbSourceData_Old;

		return uiBytesDecoded;
	}
	else
	{
		// SOF2 music, or EF1 anything...
		//
		return C_MP3Stream_Decode( lpMP3Stream );
	}
}