thug/Code/Gel/Music/ngc/divx/AUDSimplePlayer.cpp

1147 lines
34 KiB
C++
Raw Normal View History

2016-02-13 21:39:12 +00:00
#ifndef DVDETH
/*!
******************************************************************************
* \file AUDSimplePlayer.cpp
*
* \brief
* This file provides the required player control functions.
*
* \note
* This is a demonstration source only!
*
* \date
* 05/21/03
*
* \version
* 1.0
*
* \author
* Achim Moller
*
******************************************************************************
*/
/******************************************************************************
* INCLUDES
******************************************************************************/
#include <dolphin.h>
#include <string.h>
#include "AUDSimplePlayer.h"
#include "AUDSimpleAudio.h"
/******************************************************************************
* GLOABL VARIABLES
******************************************************************************/
AudSimplePlayer audio_player;
#ifndef MIN
#define MIN(a,b) ((a) < (b) ? a : b)
#endif
/******************************************************************************
* LOCAL VARIABLES
******************************************************************************/
static VidChunk workChunk ATTRIBUTE_ALIGN(32);
static void dvdDoneCallback(s32 result, DVDFileInfo *videoInfo);
/*!
******************************************************************************
* \brief
* Initializes all audio_player structures.
*
******************************************************************************
*/
void AUDSimpleInit(VAUDAllocator _cbAlloc, VAUDDeallocator _cbFree)
{
memset(&audio_player, 0, sizeof(audio_player));
audio_player.cbAlloc = _cbAlloc;
audio_player.cbFree = _cbFree;
}
/*!
******************************************************************************
* \brief
* Request an async file transfer.
*
* This function starts the transfer of the next frame into a free
* buffer.
*
******************************************************************************
*/
static void ReadFrameAsync(void)
{
if (!audio_player.error && audio_player.preFetchState == TRUE)
{
if (audio_player.currentFrameCount > audio_player.audioInfo.vaudex.frameCount - 1)
{
if (audio_player.loopMode)
{
audio_player.currentFrameCount = 0;
audio_player.nextFrameOffset = audio_player.firstFrameOffset;
audio_player.nextFrameSize = audio_player.firstFrameSize;
}
else
return;
}
audio_player.asyncDvdRunning = TRUE;
if (DVDReadAsync(&audio_player.fileHandle,
audio_player.readBuffer[audio_player.readIndex].ptr,
(s32)audio_player.nextFrameSize,
(s32)audio_player.nextFrameOffset, dvdDoneCallback) != TRUE )
{
audio_player.asyncDvdRunning = FALSE;
audio_player.error = TRUE;
}
}
}
/*!
******************************************************************************
* \brief
* DVD callback if async transfer is finished (or aborted)
*
* The idea here is to transfer ONE frame and additional 32 bytes for the
* HEADER of the NEXT frame in one transfer step. We store the size of
* the next frame, which is used in ReadFrameAsync().
*
*
* \note
* There a 32 padding bytes at the end of the .vid file. So, the reading
* of 32 additional bytes is even possible for the LAST frame. (Otherwise,
* we would 'point' out of the file)
*
* See Dolphin documentation for information about parameters.
*
******************************************************************************
*/
static void dvdDoneCallback(s32 result, DVDFileInfo * _UNUSED(videoInfo))
{
if (result == DVD_RESULT_FATAL_ERROR)
{
audio_player.error = TRUE;
return;
}
else if (result == DVD_RESULT_CANCELED)
{
return;
}
audio_player.asyncDvdRunning = FALSE;
audio_player.readBuffer[audio_player.readIndex].frameNumber = audio_player.currentFrameCount;
audio_player.readBuffer[audio_player.readIndex].size = (u32)result;
audio_player.readBuffer[audio_player.readIndex].valid = TRUE;
audio_player.currentFrameCount++;
// move file pointer
audio_player.nextFrameOffset += audio_player.nextFrameSize;
if(audio_player.currentFrameCount < audio_player.audioInfo.vaudex.frameCount)
{
// set read size for next 'FRAM' chunk
u32* nextFrameStart = (u32*)(audio_player.readBuffer[audio_player.readIndex].ptr + audio_player.nextFrameSize - 32);
// some check if file structure is okay
ASSERT(nextFrameStart[0] == VID_FCC('F','R','A','M'));
// get the size of the next 'FRAM' chunk to read
audio_player.nextFrameSize = nextFrameStart[1];
ASSERT(audio_player.nextFrameSize);
}
else
audio_player.nextFrameSize = 0; // at end of file we have a size of '0'. This should be reinitialized later
// using the size of the first frame somwhere else! Otherwise, we get an assertion
// use next buffer
audio_player.readIndex = (audio_player.readIndex + 1) % AUD_NUM_READ_BUFFERS;
// continue loading if we have a free buffer
if (!audio_player.readBuffer[audio_player.readIndex].valid)
ReadFrameAsync();
}
/*!
******************************************************************************
* \brief
* Allocate buffer memory for asynchronous dvd read
*
* \return
* TRUE if DVD buffer setup was successful.
*
******************************************************************************
*/
BOOL AUDSimpleAllocDVDBuffers(void)
{
u32 i;
u32 bufferSize;
u8* ptr;
bufferSize = audio_player.audioInfo.vaudex.maxBufferSize;
ASSERT(bufferSize);
bufferSize += VID_CHUNK_HEADER_SIZE; // 'fram' header
bufferSize += VID_CHUNK_HEADER_SIZE; // 'vidd' header
bufferSize = OSRoundUp32B(bufferSize);
ASSERT(audio_player.cbAlloc);
audio_player.readBufferBaseMem = (u8*)((*audio_player.cbAlloc)(bufferSize * AUD_NUM_READ_BUFFERS));
if(!audio_player.readBufferBaseMem)
return FALSE; // out of mem
ptr = audio_player.readBufferBaseMem;
for (i = 0; i < AUD_NUM_READ_BUFFERS ; i++)
{
audio_player.readBuffer[i].ptr = ptr;
ptr += bufferSize;
audio_player.readBuffer[i].valid = FALSE;
}
return TRUE;
}
/*!
******************************************************************************
* \brief
* Free buffer memory used for dvd read
*
* \param memFree
* Pointer to memory deallocation function
*
******************************************************************************
*/
void AUDSimpleFreeDVDBuffers(void)
{
ASSERT(audio_player.cbFree);
ASSERT(audio_player.readBufferBaseMem);
(*audio_player.cbFree)(audio_player.readBufferBaseMem);
}
/*!
******************************************************************************
* \brief
* Create a new decoder instance.
*
* \return
* TRUE if decoder creation was successful
*
******************************************************************************
*/
BOOL AUDSimpleCreateDecoder(void)
{
u32 skip;
audio_player.decoder = VAUDCreateDecoder(audio_player.cbAlloc, audio_player.cbFree, audio_player.audioInfo.vaud.maxHeap);
if(!audio_player.decoder)
return FALSE;
ASSERT(audio_player.audioHeaderChunk);
ASSERT(audio_player.audioInfo.vaud.maxHeap > 0);
ASSERT(audio_player.audioInfo.vaud.preAlloc > 0);
skip = VID_CHUNK_HEADER_SIZE + sizeof(u32) + (audio_player.audioInfo.vaudex.version > 0 ? audio_player.audioInfo.vaudex.size : sizeof(VidAUDHVAUD));
if(!VAUDInitDecoder(audio_player.decoder, audio_player.audioHeaderChunk + skip, ((VidChunk*)audio_player.audioHeaderChunk)->len - skip, audio_player.audioInfo.vaud.preAlloc))
{
VAUDDestroyDecoder(audio_player.decoder);
return FALSE;
}
return TRUE;
}
/*!
******************************************************************************
* \brief
* Destroy decoder instance.
*
* At this point the decoder returns all allocated memory by using
* the cbFree callback.
*
******************************************************************************
*/
void AUDSimpleDestroyDecoder(void)
{
ASSERT(audio_player.decoder);
VAUDDestroyDecoder(audio_player.decoder);
// Set the decoder to NULL.
audio_player.decoder = NULL;
}
static u32 readNum = 0;
/******************************************************************/
/* */
/* */
/******************************************************************/
static void AUDSimpleLoadStartDVDCallback( s32 result, DVDFileInfo* fileInfo )
{
// Deal with errors.
if( audio_player.error )
{
return;
}
audio_player.nextFrameOffset += audio_player.nextFrameSize;
audio_player.readBuffer[audio_player.readIndex].size = audio_player.nextFrameSize;
// Set read size for next 'FRAM' chunk.
u32* nextFrame = (u32*)(audio_player.readBuffer[audio_player.readIndex].ptr + audio_player.nextFrameSize - 32);
// Some sanity check if file structure is valid!
ASSERT( nextFrame[0] == VID_FCC( 'F','R','A','M' ));
audio_player.nextFrameSize = nextFrame[1];
ASSERT( audio_player.nextFrameSize );
audio_player.readBuffer[audio_player.readIndex].valid = TRUE;
audio_player.readBuffer[audio_player.readIndex].frameNumber = audio_player.currentFrameCount;
// Use next buffer.
audio_player.readIndex = (audio_player.readIndex + 1) % AUD_NUM_READ_BUFFERS;
audio_player.currentFrameCount++;
if( --readNum > 0 )
{
if( DVDReadAsync( &audio_player.fileHandle, audio_player.readBuffer[audio_player.readIndex].ptr, (s32)audio_player.nextFrameSize, (s32)audio_player.nextFrameOffset, AUDSimpleLoadStartDVDCallback ) < 0 )
{
# ifdef _DEBUG
OSReport("*** AUDSimpleLoadStart: Failed to read from file.\n");
# endif
audio_player.error = TRUE;
return;
}
}
else
{
// All done.
audio_player.loopMode = FALSE;
audio_player.preFetchState = TRUE;
}
}
/*!
******************************************************************************
* \brief
* Preload the allocated buffers.
*
* This functions fills all buffers with initial data
*
* \param loopMode
* TRUE if we want to operate in loop mode
*
* \return
* TRUE if preload was okay
*
******************************************************************************
*/
BOOL AUDSimpleLoadStart(BOOL loopMode)
{
// u32 i, readNum;
// u32 i;
// u32* nextFrame;
ASSERT( loopMode == FALSE );
if( audio_player.open && audio_player.preFetchState == FALSE )
{
readNum = AUD_NUM_READ_BUFFERS;
// In 'non-loop' mode we must take care if we have LESS frames than preloading buffers
if( !loopMode && audio_player.audioInfo.vaudex.frameCount < AUD_NUM_READ_BUFFERS )
readNum = audio_player.audioInfo.vaudex.frameCount;
// for( i = 0; i < readNum; i++ )
if( readNum > 0 )
{
// Read total 'FRAM' chunk and 32 bytes of NEXT chunk.
// if( DVDRead( &audio_player.fileHandle, ptr, (s32)audio_player.nextFrameSize, (s32)audio_player.nextFrameOffset ) < 0 )
if( DVDReadAsync( &audio_player.fileHandle, audio_player.readBuffer[audio_player.readIndex].ptr, (s32)audio_player.nextFrameSize, (s32)audio_player.nextFrameOffset, AUDSimpleLoadStartDVDCallback ) < 0 )
{
# ifdef _DEBUG
OSReport("*** AUDSimpleLoadStart: Failed to read from file.\n");
# endif
audio_player.error = TRUE;
return FALSE;
}
// audio_player.nextFrameOffset += audio_player.nextFrameSize;
// audio_player.readBuffer[audio_player.readIndex].size = audio_player.nextFrameSize;
// set read size for next 'FRAM' chunk
// nextFrame = (u32*)(audio_player.readBuffer[audio_player.readIndex].ptr + audio_player.nextFrameSize - 32);
// some sanity check if file structure is valid!
// ASSERT(nextFrame[0] == VID_FCC('F','R','A','M'));
// audio_player.nextFrameSize = nextFrame[1];
// ASSERT( audio_player.nextFrameSize );
// audio_player.readBuffer[audio_player.readIndex].valid = TRUE;
// audio_player.readBuffer[audio_player.readIndex].frameNumber = audio_player.currentFrameCount;
// Use next buffer
// audio_player.readIndex = (audio_player.readIndex + 1) % AUD_NUM_READ_BUFFERS;
// audio_player.currentFrameCount++;
// if (audio_player.currentFrameCount > audio_player.audioInfo.vaudex.frameCount - 1)
// {
// if (loopMode)
// {
// audio_player.currentFrameCount = 0;
// audio_player.nextFrameOffset = audio_player.firstFrameOffset;
// audio_player.nextFrameSize = audio_player.firstFrameSize;
// }
// }
}
// audio_player.loopMode = loopMode;
// audio_player.preFetchState = TRUE;
return TRUE;
}
return FALSE;
}
/*!
******************************************************************************
* \brief
* Stops the asynchronous loading process.
*
* \return
* TRUE if audio_player could be stopped!
*
******************************************************************************
*/
BOOL AUDSimpleLoadStop(void)
{
u32 i;
if (audio_player.open)
{
// stop preloading process
audio_player.preFetchState = FALSE;
if (audio_player.asyncDvdRunning)
{
DVDCancel(&audio_player.fileHandle.cb);
audio_player.asyncDvdRunning = FALSE;
}
// invalidate all buffers
for (i = 0 ; i < AUD_NUM_READ_BUFFERS; i++)
audio_player.readBuffer[i].valid = FALSE;
audio_player.nextFrameOffset = audio_player.firstFrameOffset;
audio_player.nextFrameSize = audio_player.firstFrameSize;
audio_player.currentFrameCount = 0;
audio_player.error = FALSE;
audio_player.readIndex = 0;
audio_player.decodeIndex = 0;
return TRUE;
}
return FALSE;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
static void AUDSimpleOpenDVDCallback( s32 result, DVDFileInfo* fileInfo )
{
static u32 fileOffset = 0;
static u32 headSize = 0;
static u32 audioInfoSize = 0;
// Deal with errors, possibly flagged as an indication to shut down immediately.
if( audio_player.error )
{
// Set this back to zero so the player will be regarded as 'free' again.
audio_player.asyncOpenCallbackStatus = 0;
return;
}
switch( audio_player.asyncOpenCallbackStatus )
{
case 1:
{
// The read of the 'VID1' chunk has completed.
fileOffset = 32;
// Check file id.
if( workChunk.id != VID_FCC('V','I','D','1' ))
{
# ifdef _DEBUG
OSReport("*** No VID1 file: '%s'\n", fileName);
# endif
DVDClose( &audio_player.fileHandle );
audio_player.asyncOpenCallbackStatus = ASYNC_OPEN_FAIL;
return;
}
// Check for correct version of vid chunk.
// If we find this version we assume a 'special' alignment and chunk ordering which may be invalid
// in another version of the file format.
if( workChunk.vid.versionMajor != 1 || workChunk.vid.versionMinor != 0 )
{
# ifdef _DEBUG
OSReport("*** Unsupported file version: major: %d, minor: %d\n", workChunk.vid.versionMajor, workChunk.vid.versionMajor);
# endif
DVDClose( &audio_player.fileHandle );
audio_player.asyncOpenCallbackStatus = ASYNC_OPEN_FAIL;
return;
}
# ifdef _DEBUG
// Sometimes, it's required to check for a special build of the VidConv converter.
{
u32 version = VID_VERSION(workChunk.vid.vidConvMajor, workChunk.vid.vidConvMinor, workChunk.vid.vidConvBuild);
if( version < VID_VERSION( 1, 0, 1 ))
OSReport("*** WARNING: Vid file created using an unsupported converter version: %d.%d.%d\n", (u32)workChunk.vid.vidConvMajor, (u32)workChunk.vid.vidConvMinor, (u32)workChunk.vid.vidConvBuild);
}
# endif
// Set callback status to indicate 'VID1' chunk is read.
audio_player.asyncOpenCallbackStatus = 2;
// Check types of chunks we have in this file.
// !!! Note that we assume start of 'HEAD' chunk at byte offset 32 from file start !!!
if( DVDReadAsync( &audio_player.fileHandle, &workChunk, 32, (s32)fileOffset, AUDSimpleOpenDVDCallback ) < 0 )
{
# ifdef _DEBUG
OSReport("*** Failed to read 'HEAD' chunk.\n");
# endif
DVDClose( &audio_player.fileHandle );
audio_player.asyncOpenCallbackStatus = ASYNC_OPEN_FAIL;
return;
}
break;
}
case 2:
{
// The read of the chunk type info has completed.
if( workChunk.id != VID_FCC('H','E','A','D' ))
{
# ifdef _DEBUG
OSReport("*** No HEAD chunk found at expected offset\n");
# endif
DVDClose( &audio_player.fileHandle );
audio_player.asyncOpenCallbackStatus = ASYNC_OPEN_FAIL;
return;
}
// Calculate the start of the first frame chunk (we know the header chunk starts at offset 32).
audio_player.nextFrameOffset = workChunk.len + 32;
// Skip 'HEAD' chunk id, len and version fields.
fileOffset += VID_CHUNK_HEADER_SIZE;
// The header chunk contains one or more header chunks for the different data types contained
// in the stream. Parse them all...
headSize = workChunk.len - VID_CHUNK_HEADER_SIZE;
audio_player.asyncOpenCallbackStatus = 3;
if( DVDReadAsync( &audio_player.fileHandle, &workChunk, 32, (s32)fileOffset, AUDSimpleOpenDVDCallback ) < 0 )
{
# ifdef _DEBUG
OSReport("*** Error reading file at offset %d\n", fileOffset);
# endif
DVDClose( &audio_player.fileHandle );
audio_player.asyncOpenCallbackStatus = ASYNC_OPEN_FAIL;
return;
}
break;
}
case 3:
{
fileOffset += 32;
headSize -= 32;
// We analyze the 1st 32 bytes of the chunk for a known header format.
if( workChunk.id == VID_FCC( 'A','U','D','H' ))
{
// Allocate memory for audio header chunk.
audio_player.audioHeaderChunk = (u8*)((*audio_player.cbAlloc)(workChunk.len));
audioInfoSize = workChunk.len - VID_CHUNK_HEADER_SIZE;
// Copy the already loaded part.
memcpy( audio_player.audioHeaderChunk, &workChunk, 32 );
workChunk.len -= 32;
// Read additional audio header bytes if the audio header is greater that 32 bytes
if( workChunk.len >= 32 )
{
ASSERT(( workChunk.len & 31 ) == 0 );
audio_player.asyncOpenCallbackStatus = 4;
if( DVDReadAsync( &audio_player.fileHandle, audio_player.audioHeaderChunk + 32, workChunk.len, (s32)fileOffset, AUDSimpleOpenDVDCallback ) < 0 )
{
# ifdef _DEBUG
OSReport("*** Error reading file at offset %d\n", fileOffset);
# endif
DVDClose( &audio_player.fileHandle );
audio_player.asyncOpenCallbackStatus = ASYNC_OPEN_FAIL;
return;
}
}
else
{
ASSERT( 0 );
}
}
else
{
ASSERT( 0 );
}
break;
}
case 4:
{
fileOffset += workChunk.len;
headSize -= workChunk.len;
// Setup and calc the number of bytes which we are allowed to copy into the audioInfo struct
memcpy( &audio_player.audioInfo, audio_player.audioHeaderChunk + VID_CHUNK_HEADER_SIZE, MIN( audioInfoSize, sizeof( audio_player.audioInfo )));
// Check if we have the correct vaud file version (>0).
if( audio_player.audioInfo.vaudex.version == 0 )
{
# ifdef _DEBUG
OSReport("*** Invalid version in vaud file.");
# endif
DVDClose( &audio_player.fileHandle );
audio_player.asyncOpenCallbackStatus = ASYNC_OPEN_FAIL;
return;
}
// We can only play audio files which have the following fields set.
// Note that in case of VIDEO files this fields are allowed to be 0.
ASSERT( audio_player.audioInfo.vaudex.maxBufferSize > 0 );
ASSERT( audio_player.audioInfo.vaudex.frameCount > 0 );
ASSERT( audio_player.audioInfo.vaudex.frameTimeMs > 0 );
// Read beginning of 1st frame chunk to get required size information.
audio_player.asyncOpenCallbackStatus = 5;
if( DVDReadAsync( &audio_player.fileHandle, &workChunk, 32 , (s32)audio_player.nextFrameOffset, AUDSimpleOpenDVDCallback ) < 0 )
{
# ifdef _DEBUG
OSReport("*** Failed to read 'FRAM' chunk.\n");
# endif
DVDClose( &audio_player.fileHandle );
audio_player.asyncOpenCallbackStatus = ASYNC_OPEN_FAIL;
return;
}
break;
}
case 5:
{
if( workChunk.id != VID_FCC('F','R','A','M') )
{
# ifdef _DEBUG
OSReport("*** No FRAM chunk found.");
# endif
audio_player.asyncOpenCallbackStatus = ASYNC_OPEN_FAIL;
DVDClose( &audio_player.fileHandle );
return;
}
// 32 bytes of this chunk are already consumed, but we want to 'preload' the NEXT chunk's FRAM header.
audio_player.nextFrameSize = workChunk.len;
audio_player.nextFrameOffset += 32;
audio_player.firstFrameOffset = audio_player.nextFrameOffset;
audio_player.firstFrameSize = audio_player.nextFrameSize;
// strncpy( audio_player.fileName, fileName, 64 );
// audio_player.fileName[63] = 0;
audio_player.open = TRUE;
audio_player.asyncOpenCallbackStatus = ASYNC_OPEN_SUCCESS;
audio_player.readIndex = 0;
audio_player.decodeIndex = 0;
audio_player.lastDecodedFrame = 0;
audio_player.error = FALSE;
audio_player.preFetchState = FALSE;
audio_player.loopMode = FALSE;
audio_player.asyncDvdRunning = FALSE;
audio_player.currentFrameCount = 0;
audio_player.readBufferBaseMem = 0;
break;
}
default:
{
ASSERT( 0 );
break;
}
}
}
/*!
******************************************************************************
* \brief
* Open video file.
*
* This functions opens a video file and parses some basic file
* information.
*
* \param fileName
* Name of file to open
*
* \return
* TRUE if file could be opened and is in valid format!
*
******************************************************************************
*/
BOOL AUDSimpleOpen( char* fileName )
{
// u32 fileOffset = 0;
// u32 headSize;
// u32 audioInfoSize;
if( audio_player.open )
{
# ifdef _DEBUG
OSReport( "*** Cannot open '%s' because audio_player already open.\n", fileName );
# endif
return FALSE;
}
// Initialise the callback status.
audio_player.asyncOpenCallbackStatus = 0;
s32 entry_num = DVDConvertPathToEntrynum( fileName );
if( entry_num == -1 )
{
# ifdef _DEBUG
OSReport( "*** Cannot find '%s'\n", filename );
# endif
return FALSE;
}
if( DVDFastOpen( entry_num, &audio_player.fileHandle ) == FALSE )
{
# ifdef _DEBUG
OSReport( "*** Cannot open: '%s'\n", fileName );
# endif
return FALSE;
}
// Set callback status to indicate file is now open.
audio_player.asyncOpenCallbackStatus = 1;
// Read 'VID1' chunk from file and check for correct version.
// if( DVDRead( &audio_player.fileHandle, &workChunk, 32, 0 ) < 0 )
if( DVDReadAsync( &audio_player.fileHandle, &workChunk, 32, 0, AUDSimpleOpenDVDCallback ) < 0 )
{
# ifdef _DEBUG
OSReport( "*** Failed to read the header for %s.\n", fileName );
# endif
DVDClose( &audio_player.fileHandle );
return FALSE;
}
strncpy( audio_player.fileName, fileName, 64 );
audio_player.fileName[63] = 0;
// Nothing more to do here.
return TRUE;
// fileOffset += 32;
// Check file id
// if( workChunk.id != VID_FCC('V','I','D','1' ))
// {
//# ifdef _DEBUG
// OSReport("*** No VID1 file: '%s'\n", fileName);
//# endif
// DVDClose( &audio_player.fileHandle );
// return FALSE;
// }
// Check for correct version of vid chunk.
// If we find this version we assume a 'special' alignment and chunk ordering which may be invalid
// in another version of the file format.
// if( workChunk.vid.versionMajor != 1 || workChunk.vid.versionMinor != 0 )
// {
//# ifdef _DEBUG
// OSReport("*** Unsupported file version: major: %d, minor: %d\n", workChunk.vid.versionMajor, workChunk.vid.versionMajor);
//# endif
// DVDClose(&audio_player.fileHandle);
// return FALSE;
// }
//# ifdef _DEBUG
// Sometimes, it's required to check for a special build of the VidConv converter.
// {
// u32 version = VID_VERSION(workChunk.vid.vidConvMajor, workChunk.vid.vidConvMinor, workChunk.vid.vidConvBuild);
// if(version < VID_VERSION(1,0,1))
// OSReport("*** WARNING: Vid file created using an unsupported converter version: %d.%d.%d\n", (u32)workChunk.vid.vidConvMajor, (u32)workChunk.vid.vidConvMinor, (u32)workChunk.vid.vidConvBuild);
// }
//# endif
// Check types of chunks we have in this file.
// !!! Note that we assume start of 'HEAD' chunk at byte offset 32 from file start !!!
// if( DVDRead( &audio_player.fileHandle, &workChunk, 32, (s32)fileOffset ) < 0 )
// {
//# ifdef _DEBUG
// OSReport("*** Failed to read 'HEAD' chunk.\n");
//# endif
// DVDClose( &audio_player.fileHandle );
// return FALSE;
// }
// if( workChunk.id != VID_FCC('H','E','A','D' ))
// {
//# ifdef _DEBUG
// OSReport("*** No HEAD chunk found at expected offset\n");
//# endif
// DVDClose(&audio_player.fileHandle);
// return FALSE;
// }
// Calculate the start of the first frame chunk
// (we know the header chunk starts at offset 32)
// audio_player.nextFrameOffset = workChunk.len + 32;
// Skip 'HEAD' chunk id, len and version fields
// fileOffset += VID_CHUNK_HEADER_SIZE;
// The header chunk contains one or more header chunks for the different data types contained
// in the stream. Parse them all...
// headSize = workChunk.len - VID_CHUNK_HEADER_SIZE;
// while( headSize >= 32 )
// {
// if( DVDRead( &audio_player.fileHandle, &workChunk, 32, (s32)fileOffset ) < 0 )
// {
//# ifdef _DEBUG
// OSReport("*** Error reading file at offset %d\n", fileOffset);
//# endif
// DVDClose(&audio_player.fileHandle);
// return FALSE;
// }
// fileOffset += 32;
// headSize -= 32;
// We analyze the 1st 32 bytes of the chunk for a known header format
// if(workChunk.id == VID_FCC('A','U','D','H'))
// {
// Allocate memory for audio header chunk
// audio_player.audioHeaderChunk = (u8*)((*audio_player.cbAlloc)(workChunk.len));
// audioInfoSize = workChunk.len - VID_CHUNK_HEADER_SIZE;
// Copy the already loaded part
// memcpy(audio_player.audioHeaderChunk, &workChunk, 32);
// workChunk.len -= 32;
// Read additional audio header bytes if the audio header is greater that 32 bytes
// if(workChunk.len >= 32)
// {
// ASSERT((workChunk.len&31)==0);
// if( DVDRead( &audio_player.fileHandle, audio_player.audioHeaderChunk + 32, workChunk.len, (s32)fileOffset ) < 0 )
// {
//# ifdef _DEBUG
// OSReport("*** Error reading file at offset %d\n", fileOffset);
//# endif
// DVDClose(&audio_player.fileHandle);
// return FALSE;
// }
// fileOffset += workChunk.len;
// headSize -= workChunk.len;
// }
// Setup and calc the number of bytes which we are allowed to copy into the audioInfo struct
// memcpy(&audio_player.audioInfo, audio_player.audioHeaderChunk+VID_CHUNK_HEADER_SIZE, MIN(audioInfoSize, sizeof(audio_player.audioInfo)));
// }
// else
// {
// // Skip unknown chunks. We already read 32 bytes for the header which we must subtract here.
// fileOffset += workChunk.len - 32;
/// headSize -= workChunk.len - 32;
// }
// }
// check if we have the correct vaud file version (>0)
// if(audio_player.audioInfo.vaudex.version == 0)
// {
//# ifdef _DEBUG
// OSReport("*** Invalid version in vaud file.");
//# endif
// DVDClose(&audio_player.fileHandle);
// return FALSE;
// }
// we can only play audio files which have the following fiels set.
// Note that in case of VIDEO files this fields are allowed to be 0.
// ASSERT(audio_player.audioInfo.vaudex.maxBufferSize > 0);
// ASSERT(audio_player.audioInfo.vaudex.frameCount > 0);
// ASSERT(audio_player.audioInfo.vaudex.frameTimeMs > 0);
// read beginning of 1st frame chunk to get required size information
// if( DVDRead( &audio_player.fileHandle, &workChunk, 32 , (s32)audio_player.nextFrameOffset ) < 0 )
// {
//# ifdef _DEBUG
// OSReport("*** Failed to read 'FRAM' chunk.\n");
//# endif
// DVDClose(&audio_player.fileHandle);
// return FALSE;
// }
// if( workChunk.id != VID_FCC('F','R','A','M') )
// {
//# ifdef _DEBUG
// OSReport("*** No FRAM chunk found.");
//# endif
// DVDClose(&audio_player.fileHandle);
// return FALSE;
// }
// audio_player.nextFrameSize = workChunk.len; // 32 bytes of this chunk are already consumed, but we want to 'preload' the NEXT chunk's FRAM header
// audio_player.nextFrameOffset += 32;
// audio_player.firstFrameOffset = audio_player.nextFrameOffset;
// audio_player.firstFrameSize = audio_player.nextFrameSize;
// strncpy(audio_player.fileName, fileName, 64);
// audio_player.fileName[63] = 0;
// audio_player.open = TRUE;
// audio_player.readIndex = 0;
// audio_player.decodeIndex = 0;
// audio_player.lastDecodedFrame = 0;
// audio_player.error = FALSE;
// audio_player.preFetchState = FALSE;
// audio_player.loopMode = FALSE;
// audio_player.asyncDvdRunning = FALSE;
// audio_player.currentFrameCount = 0;
// audio_player.readBufferBaseMem = 0;
// return TRUE;
}
/*!
******************************************************************************
* \brief
* Close open video file
*
* \return
* TRUE if file is closed sucessfully.
*
******************************************************************************
*/
BOOL AUDSimpleClose(void)
{
if (audio_player.open)
{
if (audio_player.preFetchState == FALSE)
{
if (!audio_player.asyncDvdRunning)
{
audio_player.open = FALSE;
DVDClose(&audio_player.fileHandle);
if(audio_player.audioHeaderChunk != NULL)
{
(*audio_player.cbFree)(audio_player.audioHeaderChunk);
audio_player.audioHeaderChunk = NULL;
}
return TRUE;
}
}
}
return FALSE;
}
/*!
******************************************************************************
* \brief
* Decode all frame data
*
* This function operates on the full frame input data. It forwards this
* data to the required decoder.
*
******************************************************************************
*/
BOOL AUDSimpleDecode(void)
{
BOOL enabled;
u8* chunkStart;
u32 chunkSize;
u32 frameSize;
if( audio_player.readBuffer[audio_player.decodeIndex].valid )
{
// ptr to our (pre-) loaded data INSIDE (!) 'FRAM' chunk
// (in other words, the 'FRAM' chunk itself is not visible here)
chunkStart = audio_player.readBuffer[audio_player.decodeIndex].ptr;
// usually, we read additional 32 bytes for getting info about the NEXT chunk.
// We only deal with the actual 'FRAM' chunk data here and adjust the size by 32 bytes.
frameSize = audio_player.readBuffer[audio_player.decodeIndex].size - 32;
// loop across ALL chunks inside 'FRAM'
while(frameSize >= 32)
{
chunkSize = VID_CHUNK_LEN(chunkStart);
if( VID_CHUNK_ID(chunkStart) == VID_FCC('A','U','D','D') )
{
// Get the data to the audio system...
if(! AUDSimpleAudioDecode(chunkStart + VID_CHUNK_HEADER_SIZE, chunkSize - VID_CHUNK_HEADER_SIZE))
{
#ifdef _DEBUG
OSReport("*** AUDSimpleAudioDecode failed!\n");
#endif
}
}
#ifdef _DEBUG
else
{
OSReport("*** AUDSimpleDecode: unknown chunk type!\n");
}
#endif
// goto next chunk
chunkStart += chunkSize;
frameSize -= chunkSize;
}
audio_player.lastDecodedFrame = audio_player.readBuffer[audio_player.decodeIndex].frameNumber;
audio_player.readBuffer[audio_player.decodeIndex].valid = FALSE;
audio_player.decodeIndex = (audio_player.decodeIndex + 1) % AUD_NUM_READ_BUFFERS;
// check if loading is still running
enabled = OSDisableInterrupts();
if (!audio_player.readBuffer[audio_player.readIndex].valid && !audio_player.asyncDvdRunning)
ReadFrameAsync();
OSRestoreInterrupts(enabled);
return TRUE;
}
#ifdef _DEBUG
OSReport("*** AUDSimpleDecode: No valid decode buffer found (?).\n");
#endif
return FALSE;
}
/*!
******************************************************************************
* \brief
* Change active play mask
*
******************************************************************************
*/
void AUDSimplePlayMaskChange(void)
{
static u32 myPlayMask = 0x3;
u32 maxChannels = audio_player.audioInfo.vaud.numChannels;
ASSERT(maxChannels > 0 && maxChannels <= 32);
myPlayMask <<= 1;
if(myPlayMask >= ((u32)(1<<maxChannels)))
myPlayMask |= 1;
myPlayMask &= (1<<maxChannels)-1;
AUDSimpleAudioChangePlayback(&myPlayMask, 1);
}
/*!
******************************************************************************
* \brief
* Get audio sample rate in Hz.
*
******************************************************************************
*/
u32 AUDSimpleGetAudioSampleRate(void)
{
return(audio_player.audioInfo.vaud.frq);
}
/*!
******************************************************************************
* \brief
* Return time in ms of one audio frame
*
******************************************************************************
*/
extern u32 AUDSimpleGetFrameTime(void)
{
return(audio_player.audioInfo.vaudex.frameTimeMs);
}
/*!
******************************************************************************
* \brief
* Check for drive status
*
******************************************************************************
*/
BOOL AUDSimpleCheckDVDError(void)
{
switch (DVDGetDriveStatus())
{
case DVD_STATE_FATAL_ERROR:
{
OSReport("DVDGetDriveStatus()=DVD_STATE_FATAL_ERROR\n");
break;
}
case DVD_STATE_NO_DISK:
{
OSReport("DVDGetDriveStatus()=DVD_STATE_NO_DISK\n");
break;
}
case DVD_STATE_COVER_OPEN:
{
OSReport("DVDGetDriveStatus()=DVD_STATE_COVER_OPEN\n");
break;
}
case DVD_STATE_WRONG_DISK:
{
OSReport("DVDGetDriveStatus()=DVD_STATE_WRONG_DISK\n");
break;
}
case DVD_STATE_RETRY:
{
OSReport("DVDGetDriveStatus()=DVD_STATE_RETRY\n");
break;
}
default:
return(TRUE);
}
return(FALSE);
}
#endif // DVDETH