mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-28 04:31:06 +00:00
c1a4db611b
Original commit message from CVS: Add monkeyaudio plugin
283 lines
9.1 KiB
C++
283 lines
9.1 KiB
C++
#include "All.h"
|
|
#include "WAVInputSource.h"
|
|
#include IO_HEADER_FILE
|
|
#include "MACLib.h"
|
|
#include "GlobalFunctions.h"
|
|
|
|
struct RIFF_HEADER
|
|
{
|
|
char cRIFF[4]; // the characters 'RIFF' indicating that it's a RIFF file
|
|
unsigned long nBytes; // the number of bytes following this header
|
|
};
|
|
|
|
struct DATA_TYPE_ID_HEADER
|
|
{
|
|
char cDataTypeID[4]; // should equal 'WAVE' for a WAV file
|
|
};
|
|
|
|
struct WAV_FORMAT_HEADER
|
|
{
|
|
unsigned short nFormatTag; // the format of the WAV...should equal 1 for a PCM file
|
|
unsigned short nChannels; // the number of channels
|
|
unsigned long nSamplesPerSecond; // the number of samples per second
|
|
unsigned long nBytesPerSecond; // the bytes per second
|
|
unsigned short nBlockAlign; // block alignment
|
|
unsigned short nBitsPerSample; // the number of bits per sample
|
|
};
|
|
|
|
struct RIFF_CHUNK_HEADER
|
|
{
|
|
char cChunkLabel[4]; // should equal "data" indicating the data chunk
|
|
unsigned long nChunkBytes; // the bytes of the chunk
|
|
};
|
|
|
|
|
|
CInputSource * CreateInputSource(const char * pSourceName, WAVEFORMATEX * pwfeSource, int * pTotalBlocks, int * pHeaderBytes, int * pTerminatingBytes, int * pErrorCode)
|
|
{
|
|
// error check the parameters
|
|
if ((pSourceName == NULL) || (strlen(pSourceName) == 0))
|
|
{
|
|
if (pErrorCode) *pErrorCode = ERROR_BAD_PARAMETER;
|
|
return NULL;
|
|
}
|
|
// Removed bad code which avoid compressing of files if extention is not standard
|
|
#if 0
|
|
// get the extension
|
|
const char * pExtension = &pSourceName[strlen(pSourceName)];
|
|
while ((pExtension > pSourceName) && (*pExtension != '.'))
|
|
pExtension--;
|
|
|
|
// create the proper input source
|
|
if (_stricmp(pExtension, ".wav") == 0)
|
|
{
|
|
if (pErrorCode) *pErrorCode = ERROR_SUCCESS;
|
|
#endif
|
|
return new CWAVInputSource(pSourceName, pwfeSource, pTotalBlocks, pHeaderBytes, pTerminatingBytes, pErrorCode);
|
|
#if 0
|
|
}
|
|
else
|
|
{
|
|
if (pErrorCode) *pErrorCode = ERROR_INVALID_INPUT_FILE;
|
|
return NULL;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
CWAVInputSource::CWAVInputSource(CIO * pIO, WAVEFORMATEX * pwfeSource, int * pTotalBlocks, int * pHeaderBytes, int * pTerminatingBytes, int * pErrorCode)
|
|
: CInputSource(pIO, pwfeSource, pTotalBlocks, pHeaderBytes, pTerminatingBytes, pErrorCode)
|
|
{
|
|
m_bIsValid = FALSE;
|
|
|
|
if (pIO == NULL || pwfeSource == NULL)
|
|
{
|
|
if (pErrorCode) *pErrorCode = ERROR_BAD_PARAMETER;
|
|
return;
|
|
}
|
|
|
|
m_spIO.Assign(pIO, FALSE, FALSE);
|
|
|
|
int nRetVal = AnalyzeSource();
|
|
if (nRetVal == ERROR_SUCCESS)
|
|
{
|
|
// fill in the parameters
|
|
if (pwfeSource) memcpy(pwfeSource, &m_wfeSource, sizeof(WAVEFORMATEX));
|
|
if (pTotalBlocks) *pTotalBlocks = m_nDataBytes / m_wfeSource.nBlockAlign;
|
|
if (pHeaderBytes) *pHeaderBytes = m_nHeaderBytes;
|
|
if (pTerminatingBytes) *pTerminatingBytes = m_nTerminatingBytes;
|
|
|
|
m_bIsValid = TRUE;
|
|
}
|
|
|
|
if (pErrorCode) *pErrorCode = nRetVal;
|
|
}
|
|
|
|
CWAVInputSource::CWAVInputSource(const char * pSourceName, WAVEFORMATEX * pwfeSource, int * pTotalBlocks, int * pHeaderBytes, int * pTerminatingBytes, int * pErrorCode)
|
|
: CInputSource(pSourceName, pwfeSource, pTotalBlocks, pHeaderBytes, pTerminatingBytes, pErrorCode)
|
|
{
|
|
m_bIsValid = FALSE;
|
|
|
|
if (pSourceName == NULL || pwfeSource == NULL)
|
|
{
|
|
if (pErrorCode) *pErrorCode = ERROR_BAD_PARAMETER;
|
|
return;
|
|
}
|
|
|
|
m_spIO.Assign(new IO_CLASS_NAME);
|
|
if (m_spIO->Open(pSourceName) != ERROR_SUCCESS)
|
|
{
|
|
m_spIO.Delete();
|
|
if (pErrorCode) *pErrorCode = ERROR_INVALID_INPUT_FILE;
|
|
return;
|
|
}
|
|
|
|
int nRetVal = AnalyzeSource();
|
|
if (nRetVal == ERROR_SUCCESS)
|
|
{
|
|
// fill in the parameters
|
|
if (pwfeSource) memcpy(pwfeSource, &m_wfeSource, sizeof(WAVEFORMATEX));
|
|
if (pTotalBlocks) *pTotalBlocks = m_nDataBytes / m_wfeSource.nBlockAlign;
|
|
if (pHeaderBytes) *pHeaderBytes = m_nHeaderBytes;
|
|
if (pTerminatingBytes) *pTerminatingBytes = m_nTerminatingBytes;
|
|
|
|
m_bIsValid = TRUE;
|
|
}
|
|
|
|
if (pErrorCode) *pErrorCode = nRetVal;
|
|
}
|
|
|
|
CWAVInputSource::~CWAVInputSource()
|
|
{
|
|
|
|
|
|
}
|
|
|
|
int CWAVInputSource::AnalyzeSource()
|
|
{
|
|
// seek to the beginning (just in case)
|
|
m_spIO->Seek(0, FILE_BEGIN);
|
|
|
|
// get the file size
|
|
m_nFileBytes = m_spIO->GetSize();
|
|
|
|
// get the RIFF header
|
|
RIFF_HEADER RIFFHeader;
|
|
RETURN_ON_ERROR(ReadSafe(m_spIO, &RIFFHeader, sizeof(RIFFHeader)))
|
|
|
|
// make sure the RIFF header is valid
|
|
if (!(RIFFHeader.cRIFF[0] == 'R' && RIFFHeader.cRIFF[1] == 'I' && RIFFHeader.cRIFF[2] == 'F' && RIFFHeader.cRIFF[3] == 'F'))
|
|
return ERROR_INVALID_INPUT_FILE;
|
|
|
|
// read the data type header
|
|
DATA_TYPE_ID_HEADER DataTypeIDHeader;
|
|
RETURN_ON_ERROR(ReadSafe(m_spIO, &DataTypeIDHeader, sizeof(DataTypeIDHeader)))
|
|
|
|
// make sure it's the right data type
|
|
if (!(DataTypeIDHeader.cDataTypeID[0] == 'W' && DataTypeIDHeader.cDataTypeID[1] == 'A' && DataTypeIDHeader.cDataTypeID[2] == 'V' && DataTypeIDHeader.cDataTypeID[3] == 'E'))
|
|
return ERROR_INVALID_INPUT_FILE;
|
|
|
|
// find the 'fmt ' chunk
|
|
RIFF_CHUNK_HEADER RIFFChunkHeader;
|
|
RETURN_ON_ERROR(ReadSafe(m_spIO, &RIFFChunkHeader, sizeof(RIFFChunkHeader)))
|
|
|
|
while (!(RIFFChunkHeader.cChunkLabel[0] == 'f' && RIFFChunkHeader.cChunkLabel[1] == 'm' && RIFFChunkHeader.cChunkLabel[2] == 't' && RIFFChunkHeader.cChunkLabel[3] == ' '))
|
|
{
|
|
// move the file pointer to the end of this chunk
|
|
m_spIO->Seek(RIFFChunkHeader.nChunkBytes, FILE_CURRENT);
|
|
|
|
// check again for the data chunk
|
|
RETURN_ON_ERROR(ReadSafe(m_spIO, &RIFFChunkHeader, sizeof(RIFFChunkHeader)))
|
|
}
|
|
|
|
// read the format info
|
|
WAV_FORMAT_HEADER WAVFormatHeader;
|
|
RETURN_ON_ERROR(ReadSafe(m_spIO, &WAVFormatHeader, sizeof(WAVFormatHeader)))
|
|
|
|
// error check the header to see if we support it
|
|
if (WAVFormatHeader.nFormatTag != 1)
|
|
return ERROR_INVALID_INPUT_FILE;
|
|
|
|
// copy the format information to the WAVEFORMATEX passed in
|
|
FillWaveFormatEx(&m_wfeSource, WAVFormatHeader.nSamplesPerSecond, WAVFormatHeader.nBitsPerSample, WAVFormatHeader.nChannels);
|
|
|
|
// skip over any extra data in the header
|
|
int nWAVFormatHeaderExtra = RIFFChunkHeader.nChunkBytes - sizeof(WAVFormatHeader);
|
|
if (nWAVFormatHeaderExtra < 0)
|
|
return ERROR_INVALID_INPUT_FILE;
|
|
else
|
|
//m_spIO->Seek(nWAVFormatHeaderExtra, FILE_CURRENT);
|
|
|
|
// find the data chunk
|
|
RETURN_ON_ERROR(ReadSafe(m_spIO, &RIFFChunkHeader, sizeof(RIFFChunkHeader)))
|
|
|
|
while (!(RIFFChunkHeader.cChunkLabel[0] == 'd' && RIFFChunkHeader.cChunkLabel[1] == 'a' && RIFFChunkHeader.cChunkLabel[2] == 't' && RIFFChunkHeader.cChunkLabel[3] == 'a'))
|
|
{
|
|
// move the file pointer to the end of this chunk
|
|
m_spIO->Seek(RIFFChunkHeader.nChunkBytes, FILE_CURRENT);
|
|
|
|
// check again for the data chunk
|
|
RETURN_ON_ERROR(ReadSafe(m_spIO, &RIFFChunkHeader, sizeof(RIFFChunkHeader)))
|
|
}
|
|
|
|
// we're at the data block
|
|
m_nHeaderBytes = m_spIO->GetPosition();
|
|
m_nDataBytes = RIFFChunkHeader.nChunkBytes;
|
|
if (m_nDataBytes < 0)
|
|
m_nDataBytes = m_nFileBytes - m_nHeaderBytes;
|
|
|
|
// make sure the data bytes is a whole number of blocks
|
|
if ((m_nDataBytes % m_wfeSource.nBlockAlign) != 0)
|
|
return ERROR_INVALID_INPUT_FILE;
|
|
|
|
// calculate the terminating byts
|
|
m_nTerminatingBytes = m_nFileBytes - m_nDataBytes - m_nHeaderBytes;
|
|
|
|
// we made it this far, everything must be cool
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
int CWAVInputSource::GetData(unsigned char * pBuffer, int nBlocks, int * pBlocksRetrieved)
|
|
{
|
|
if (!m_bIsValid) return ERROR_UNDEFINED;
|
|
|
|
int nBytes = (m_wfeSource.nBlockAlign * nBlocks);
|
|
unsigned int nBytesRead = 0;
|
|
|
|
if (m_spIO->Read(pBuffer, nBytes, &nBytesRead) != ERROR_SUCCESS)
|
|
return ERROR_IO_READ;
|
|
|
|
if (pBlocksRetrieved) *pBlocksRetrieved = (nBytesRead / m_wfeSource.nBlockAlign);
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
int CWAVInputSource::GetHeaderData(unsigned char * pBuffer)
|
|
{
|
|
if (!m_bIsValid) return ERROR_UNDEFINED;
|
|
|
|
int nRetVal = ERROR_SUCCESS;
|
|
|
|
if (m_nHeaderBytes > 0)
|
|
{
|
|
int nOriginalFileLocation = m_spIO->GetPosition();
|
|
|
|
m_spIO->Seek(0, FILE_BEGIN);
|
|
|
|
unsigned int nBytesRead = 0;
|
|
int nReadRetVal = m_spIO->Read(pBuffer, m_nHeaderBytes, &nBytesRead);
|
|
|
|
if ((nReadRetVal != ERROR_SUCCESS) || (m_nHeaderBytes != int(nBytesRead)))
|
|
{
|
|
nRetVal = ERROR_UNDEFINED;
|
|
}
|
|
|
|
m_spIO->Seek(nOriginalFileLocation, FILE_BEGIN);
|
|
}
|
|
|
|
return nRetVal;
|
|
}
|
|
|
|
int CWAVInputSource::GetTerminatingData(unsigned char * pBuffer)
|
|
{
|
|
if (!m_bIsValid) return ERROR_UNDEFINED;
|
|
|
|
int nRetVal = ERROR_SUCCESS;
|
|
|
|
if (m_nTerminatingBytes > 0)
|
|
{
|
|
int nOriginalFileLocation = m_spIO->GetPosition();
|
|
|
|
m_spIO->Seek(-m_nTerminatingBytes, FILE_END);
|
|
|
|
unsigned int nBytesRead = 0;
|
|
int nReadRetVal = m_spIO->Read(pBuffer, m_nTerminatingBytes, &nBytesRead);
|
|
|
|
if ((nReadRetVal != ERROR_SUCCESS) || (m_nTerminatingBytes != int(nBytesRead)))
|
|
{
|
|
nRetVal = ERROR_UNDEFINED;
|
|
}
|
|
|
|
m_spIO->Seek(nOriginalFileLocation, FILE_BEGIN);
|
|
}
|
|
|
|
return nRetVal;
|
|
}
|