815 lines
22 KiB
C
815 lines
22 KiB
C
/*
|
|
* imaadp32.drv - IMA4 codec driver
|
|
*
|
|
* Copyright 2001 Hidenori Takeshima
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*
|
|
*
|
|
* FIXME - no encoding.
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#include "windef.h"
|
|
#include "winbase.h"
|
|
#include "wingdi.h"
|
|
#include "winnls.h"
|
|
#include "winuser.h"
|
|
#include "mmsystem.h"
|
|
#include "msacm.h"
|
|
|
|
#include "wine/debug.h"
|
|
|
|
WINE_DEFAULT_DEBUG_CHANNEL(imaadp32);
|
|
|
|
|
|
/***********************************************************************/
|
|
|
|
#define ACMDM_DRIVER_NOTIFY (ACMDM_BASE + 1)
|
|
#define ACMDM_DRIVER_DETAILS (ACMDM_BASE + 10)
|
|
|
|
#define ACMDM_HARDWARE_WAVE_CAPS_INPUT (ACMDM_BASE + 20)
|
|
#define ACMDM_HARDWARE_WAVE_CAPS_OUTPUT (ACMDM_BASE + 21)
|
|
|
|
#define ACMDM_FORMATTAG_DETAILS (ACMDM_BASE + 25)
|
|
#define ACMDM_FORMAT_DETAILS (ACMDM_BASE + 26)
|
|
#define ACMDM_FORMAT_SUGGEST (ACMDM_BASE + 27)
|
|
|
|
#define ACMDM_FILTERTAG_DETAILS (ACMDM_BASE + 50)
|
|
#define ACMDM_FILTER_DETAILS (ACMDM_BASE + 51)
|
|
|
|
#define ACMDM_STREAM_OPEN (ACMDM_BASE + 76)
|
|
#define ACMDM_STREAM_CLOSE (ACMDM_BASE + 77)
|
|
#define ACMDM_STREAM_SIZE (ACMDM_BASE + 78)
|
|
#define ACMDM_STREAM_CONVERT (ACMDM_BASE + 79)
|
|
#define ACMDM_STREAM_RESET (ACMDM_BASE + 80)
|
|
#define ACMDM_STREAM_PREPARE (ACMDM_BASE + 81)
|
|
#define ACMDM_STREAM_UNPREPARE (ACMDM_BASE + 82)
|
|
#define ACMDM_STREAM_UPDATE (ACMDM_BASE + 83)
|
|
|
|
typedef struct _ACMDRVSTREAMINSTANCE
|
|
{
|
|
DWORD cbStruct;
|
|
PWAVEFORMATEX pwfxSrc;
|
|
PWAVEFORMATEX pwfxDst;
|
|
PWAVEFILTER pwfltr;
|
|
DWORD dwCallback;
|
|
DWORD dwInstance;
|
|
DWORD fdwOpen;
|
|
DWORD fdwDriver;
|
|
DWORD dwDriver;
|
|
HACMSTREAM has;
|
|
} ACMDRVSTREAMINSTANCE, *PACMDRVSTREAMINSTANCE;
|
|
|
|
typedef struct _ACMDRVSTREAMHEADER *PACMDRVSTREAMHEADER;
|
|
typedef struct _ACMDRVSTREAMHEADER {
|
|
DWORD cbStruct;
|
|
DWORD fdwStatus;
|
|
DWORD dwUser;
|
|
LPBYTE pbSrc;
|
|
DWORD cbSrcLength;
|
|
DWORD cbSrcLengthUsed;
|
|
DWORD dwSrcUser;
|
|
LPBYTE pbDst;
|
|
DWORD cbDstLength;
|
|
DWORD cbDstLengthUsed;
|
|
DWORD dwDstUser;
|
|
|
|
DWORD fdwConvert;
|
|
PACMDRVSTREAMHEADER *padshNext;
|
|
DWORD fdwDriver;
|
|
DWORD dwDriver;
|
|
|
|
/* Internal fields for ACM */
|
|
DWORD fdwPrepared;
|
|
DWORD dwPrepared;
|
|
LPBYTE pbPreparedSrc;
|
|
DWORD cbPreparedSrcLength;
|
|
LPBYTE pbPreparedDst;
|
|
DWORD cbPreparedDstLength;
|
|
} ACMDRVSTREAMHEADER;
|
|
|
|
typedef struct _ACMDRVSTREAMSIZE
|
|
{
|
|
DWORD cbStruct;
|
|
DWORD fdwSize;
|
|
DWORD cbSrcLength;
|
|
DWORD cbDstLength;
|
|
} ACMDRVSTREAMSIZE, *PACMDRVSTREAMSIZE;
|
|
|
|
typedef struct _ACMDRVFORMATSUGGEST
|
|
{
|
|
DWORD cbStruct;
|
|
DWORD fdwSuggest;
|
|
PWAVEFORMATEX pwfxSrc;
|
|
DWORD cbwfxSrc;
|
|
PWAVEFORMATEX pwfxDst;
|
|
DWORD cbwfxDst;
|
|
} ACMDRVFORMATSUGGEST, *PACMDRVFORMATSUGGEST;
|
|
|
|
|
|
|
|
|
|
/***********************************************************************/
|
|
|
|
enum CodecType
|
|
{
|
|
CodecType_Invalid,
|
|
CodecType_EncIMAADPCM,
|
|
CodecType_DecIMAADPCM,
|
|
};
|
|
|
|
typedef struct CodecImpl
|
|
{
|
|
int dummy;
|
|
} CodecImpl;
|
|
|
|
/***********************************************************************/
|
|
|
|
|
|
static const int ima_step[88+1] =
|
|
{
|
|
/* from Y.Ajima's WAVFMT.TXT */
|
|
7, 8, 9, 10, 11, 12, 13, 14,
|
|
16, 17, 19, 21, 23, 25, 28, 31,
|
|
34, 37, 41, 45, 50, 55, 60, 66,
|
|
73, 80, 88, 97, 107, 118, 130, 143,
|
|
157, 173, 190, 209, 230, 253, 279, 307,
|
|
337, 371, 408, 449, 494, 544, 598, 658,
|
|
724, 796, 876, 963, 1060, 1166, 1282, 1411,
|
|
1552, 1707, 1878, 2066, 2272, 2499, 2749, 3024,
|
|
3327, 3660, 4026, 4428, 4871, 5358, 5894, 6484,
|
|
7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899,
|
|
15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767
|
|
};
|
|
|
|
static const int ima_indexupdate[8*2] =
|
|
{
|
|
/* from Y.Ajima's WAVFMT.TXT */
|
|
-1,-1,-1,-1, 2, 4, 6, 8,
|
|
-1,-1,-1,-1, 2, 4, 6, 8,
|
|
};
|
|
|
|
static int stepindex_to_diff( int stepindex, int input )
|
|
{
|
|
/* from Y.Ajima's WAVFMT.TXT */
|
|
int absdiff;
|
|
|
|
absdiff = (ima_step[stepindex]*((input&0x7)*2+1)) >> 3;
|
|
return (input&0x8) ? (-absdiff) : absdiff;
|
|
}
|
|
|
|
static int update_stepindex( int oldindex, int input )
|
|
{
|
|
int index;
|
|
|
|
index = oldindex + ima_indexupdate[input];
|
|
return (index < 0) ? 0 : (index > 88) ? 88 : index;
|
|
}
|
|
|
|
static void decode_ima_block( int channels, int samplesperblock, SHORT* pDst, BYTE* pSrc )
|
|
{
|
|
int samp[2];
|
|
int stepindex[2];
|
|
int inputs[8];
|
|
int n,k,diff;
|
|
|
|
for ( n = 0; n < channels; n++ )
|
|
{
|
|
samp[n] = *(SHORT*)pSrc; pSrc += sizeof(SHORT);
|
|
stepindex[n] = *pSrc; pSrc += sizeof(SHORT);
|
|
*pDst++ = samp[n];
|
|
}
|
|
samplesperblock --;
|
|
|
|
while ( samplesperblock >= 8 )
|
|
{
|
|
for ( n = 0; n < channels; n++ )
|
|
{
|
|
for ( k = 0; k < 4; k++ )
|
|
{
|
|
inputs[k*2+0] = (*pSrc) & 0xf;
|
|
inputs[k*2+1] = (*pSrc) >> 4;
|
|
pSrc ++;
|
|
}
|
|
for ( k = 0; k < 8; k++ )
|
|
{
|
|
diff = stepindex_to_diff( stepindex[n], inputs[k] );
|
|
stepindex[n] = update_stepindex( stepindex[n], inputs[k] );
|
|
diff += samp[n];
|
|
if ( diff < -32768 ) diff = -32768;
|
|
if ( diff > 32767 ) diff = 32767;
|
|
samp[n] = diff;
|
|
pDst[k*channels+n] = samp[n];
|
|
}
|
|
}
|
|
|
|
pDst += channels*8;
|
|
samplesperblock -= 8;
|
|
}
|
|
}
|
|
|
|
static LONG IMAADPCM32_Decode( int channels, int blockalign, int samplesperblock, BYTE* pbDst, DWORD cbDstLength, DWORD* pcbDstLengthUsed, BYTE* pbSrc, DWORD cbSrcLength, DWORD* pcbSrcLengthUsed )
|
|
{
|
|
DWORD cbDstLengthUsed = 0;
|
|
DWORD cbSrcLengthUsed = 0;
|
|
int dstblocksize;
|
|
|
|
dstblocksize = samplesperblock*channels*sizeof(SHORT);
|
|
while ( cbDstLength >= dstblocksize && cbSrcLength >= blockalign )
|
|
{
|
|
decode_ima_block( channels, samplesperblock, (SHORT*)pbDst, pbSrc );
|
|
pbDst += dstblocksize;
|
|
cbDstLength -= dstblocksize;
|
|
cbDstLengthUsed += dstblocksize;
|
|
pbSrc += blockalign;
|
|
cbSrcLength -= blockalign;
|
|
cbSrcLengthUsed += blockalign;
|
|
}
|
|
|
|
*pcbSrcLengthUsed = cbSrcLengthUsed;
|
|
*pcbDstLengthUsed = cbDstLengthUsed;
|
|
|
|
return MMSYSERR_NOERROR;
|
|
}
|
|
|
|
|
|
/***********************************************************************/
|
|
|
|
static LONG Codec_DrvQueryConfigure( CodecImpl* This )
|
|
{
|
|
return MMSYSERR_NOTSUPPORTED;
|
|
}
|
|
|
|
static LONG Codec_DrvConfigure( CodecImpl* This, HWND hwnd, DRVCONFIGINFO* pinfo )
|
|
{
|
|
return MMSYSERR_NOTSUPPORTED;
|
|
}
|
|
|
|
static LONG Codec_DriverDetails( ACMDRIVERDETAILSW* pDrvDetails )
|
|
{
|
|
if ( pDrvDetails->cbStruct < sizeof(ACMDRIVERDETAILSW) )
|
|
return MMSYSERR_INVALPARAM;
|
|
|
|
ZeroMemory( pDrvDetails, sizeof(ACMDRIVERDETAILSW) );
|
|
pDrvDetails->cbStruct = sizeof(ACMDRIVERDETAILSW);
|
|
|
|
pDrvDetails->fccType = ACMDRIVERDETAILS_FCCTYPE_AUDIOCODEC;
|
|
pDrvDetails->fccComp = ACMDRIVERDETAILS_FCCCOMP_UNDEFINED;
|
|
pDrvDetails->wMid = 0xff; /* FIXME? */
|
|
pDrvDetails->wPid = 0x00; /* FIXME? */
|
|
pDrvDetails->vdwACM = 0x01000000; /* FIXME? */
|
|
pDrvDetails->vdwDriver = 0x01000000; /* FIXME? */
|
|
pDrvDetails->fdwSupport = ACMDRIVERDETAILS_SUPPORTF_CODEC;
|
|
pDrvDetails->cFormatTags = 2;
|
|
pDrvDetails->cFilterTags = 0;
|
|
pDrvDetails->hicon = (HICON)NULL;
|
|
MultiByteToWideChar( CP_ACP, 0, "WineIMA", -1,
|
|
pDrvDetails->szShortName,
|
|
sizeof(pDrvDetails->szShortName)/sizeof(WCHAR) );
|
|
MultiByteToWideChar( CP_ACP, 0, "Wine IMA codec", -1,
|
|
pDrvDetails->szLongName,
|
|
sizeof(pDrvDetails->szLongName)/sizeof(WCHAR) );
|
|
MultiByteToWideChar( CP_ACP, 0, "Brought to you by the Wine team...", -1,
|
|
pDrvDetails->szCopyright,
|
|
sizeof(pDrvDetails->szCopyright)/sizeof(WCHAR) );
|
|
MultiByteToWideChar( CP_ACP, 0, "Refer to LICENSE file", -1,
|
|
pDrvDetails->szLicensing,
|
|
sizeof(pDrvDetails->szLicensing)/sizeof(WCHAR) );
|
|
pDrvDetails->szFeatures[0] = 0;
|
|
|
|
return MMSYSERR_NOERROR;
|
|
}
|
|
|
|
static LONG Codec_QueryAbout( void )
|
|
{
|
|
return MMSYSERR_NOTSUPPORTED;
|
|
}
|
|
|
|
static LONG Codec_About( HWND hwnd )
|
|
{
|
|
return MMSYSERR_NOTSUPPORTED;
|
|
}
|
|
|
|
/***********************************************************************/
|
|
|
|
static LONG Codec_FormatTagDetails( CodecImpl* This, ACMFORMATTAGDETAILSW* pFmtTagDetails, DWORD dwFlags )
|
|
{
|
|
FIXME( "enumerate tags\n" );
|
|
|
|
switch ( dwFlags )
|
|
{
|
|
case ACM_FORMATTAGDETAILSF_INDEX:
|
|
switch ( pFmtTagDetails->dwFormatTagIndex )
|
|
{
|
|
case 0:
|
|
pFmtTagDetails->dwFormatTag = 0x11; /* IMA ADPCM */
|
|
break;
|
|
case 1:
|
|
pFmtTagDetails->dwFormatTag = 1; /* PCM */
|
|
break;
|
|
default:
|
|
return ACMERR_NOTPOSSIBLE;
|
|
}
|
|
break;
|
|
case ACM_FORMATTAGDETAILSF_FORMATTAG:
|
|
switch ( pFmtTagDetails->dwFormatTag )
|
|
{
|
|
case 0x11: /* IMA ADPCM */
|
|
pFmtTagDetails->dwFormatTagIndex = 0;
|
|
break;
|
|
case 1: /* PCM */
|
|
pFmtTagDetails->dwFormatTagIndex = 1;
|
|
break;
|
|
default:
|
|
return ACMERR_NOTPOSSIBLE;
|
|
}
|
|
break;
|
|
case ACM_FORMATTAGDETAILSF_LARGESTSIZE:
|
|
if ( pFmtTagDetails->dwFormatTag != 0 &&
|
|
pFmtTagDetails->dwFormatTag != 1 &&
|
|
pFmtTagDetails->dwFormatTag != 0x11 )
|
|
return ACMERR_NOTPOSSIBLE;
|
|
pFmtTagDetails->dwFormatTagIndex = 0;
|
|
break;
|
|
default:
|
|
return MMSYSERR_NOTSUPPORTED;
|
|
}
|
|
|
|
pFmtTagDetails->fdwSupport = ACMDRIVERDETAILS_SUPPORTF_CODEC;
|
|
pFmtTagDetails->cbFormatSize = sizeof(WAVEFORMATEX);
|
|
pFmtTagDetails->cStandardFormats = 2; /* FIXME */
|
|
pFmtTagDetails->szFormatTag[0] = 0; /* FIXME */
|
|
|
|
return MMSYSERR_NOERROR;
|
|
}
|
|
|
|
static LONG Codec_FormatDetails( CodecImpl* This, ACMFORMATDETAILSW* pFmtDetails, DWORD dwFlags )
|
|
{
|
|
FIXME( "enumerate standard formats\n" );
|
|
|
|
if ( pFmtDetails->cbStruct < sizeof(ACMFORMATDETAILSW) )
|
|
return MMSYSERR_INVALPARAM;
|
|
pFmtDetails->cbStruct = sizeof(ACMFORMATDETAILSW);
|
|
|
|
switch ( dwFlags )
|
|
{
|
|
case ACM_FORMATDETAILSF_INDEX:
|
|
switch ( pFmtDetails->dwFormatIndex )
|
|
{
|
|
case 0:
|
|
pFmtDetails->dwFormatTag = 0x11; /* IMA ADPCM */
|
|
break;
|
|
case 1:
|
|
pFmtDetails->dwFormatTag = 1; /* PCM */
|
|
break;
|
|
default:
|
|
return MMSYSERR_INVALPARAM;
|
|
}
|
|
break;
|
|
case ACM_FORMATDETAILSF_FORMAT:
|
|
switch ( pFmtDetails->dwFormatTag )
|
|
{
|
|
case 0x11: /* IMA ADPCM */
|
|
pFmtDetails->dwFormatIndex = 0;
|
|
break;
|
|
case 1: /* PCM */
|
|
pFmtDetails->dwFormatIndex = 1;
|
|
break;
|
|
default:
|
|
return ACMERR_NOTPOSSIBLE;
|
|
}
|
|
break;
|
|
default:
|
|
return MMSYSERR_NOTSUPPORTED;
|
|
}
|
|
|
|
pFmtDetails->fdwSupport = ACMDRIVERDETAILS_SUPPORTF_CODEC;
|
|
pFmtDetails->pwfx->wFormatTag = pFmtDetails->dwFormatTag;
|
|
pFmtDetails->pwfx->nChannels = 1;
|
|
pFmtDetails->pwfx->nSamplesPerSec = 11025;
|
|
pFmtDetails->pwfx->wBitsPerSample = 4;
|
|
if ( pFmtDetails->dwFormatTag == 1 )
|
|
{
|
|
pFmtDetails->cbwfx = sizeof(PCMWAVEFORMAT);
|
|
}
|
|
else
|
|
{
|
|
pFmtDetails->pwfx->cbSize = sizeof(WORD);
|
|
pFmtDetails->cbwfx = sizeof(WAVEFORMATEX) + sizeof(WORD);
|
|
}
|
|
pFmtDetails->szFormat[0] = 0; /* FIXME */
|
|
|
|
return MMSYSERR_NOERROR;
|
|
}
|
|
|
|
|
|
static LONG Codec_FormatSuggest( CodecImpl* This, ACMDRVFORMATSUGGEST* pFmtSuggest )
|
|
{
|
|
DWORD fdwSuggest;
|
|
|
|
FIXME( "get suggested format\n" );
|
|
|
|
if ( pFmtSuggest->cbStruct != sizeof(ACMDRVFORMATSUGGEST) )
|
|
return MMSYSERR_INVALPARAM;
|
|
|
|
if ( pFmtSuggest->cbwfxSrc < sizeof(PCMWAVEFORMAT) ||
|
|
pFmtSuggest->cbwfxDst < sizeof(PCMWAVEFORMAT) )
|
|
return MMSYSERR_INVALPARAM;
|
|
|
|
fdwSuggest = pFmtSuggest->fdwSuggest;
|
|
|
|
if ( fdwSuggest & ACM_FORMATSUGGESTF_NCHANNELS )
|
|
{
|
|
if ( pFmtSuggest->pwfxSrc->nChannels != pFmtSuggest->pwfxDst->nChannels )
|
|
return ACMERR_NOTPOSSIBLE;
|
|
fdwSuggest &= ~ACM_FORMATSUGGESTF_NCHANNELS;
|
|
}
|
|
|
|
if ( fdwSuggest & ACM_FORMATSUGGESTF_NSAMPLESPERSEC )
|
|
{
|
|
if ( pFmtSuggest->pwfxSrc->nSamplesPerSec != pFmtSuggest->pwfxDst->nSamplesPerSec )
|
|
return ACMERR_NOTPOSSIBLE;
|
|
fdwSuggest &= ~ACM_FORMATSUGGESTF_NSAMPLESPERSEC;
|
|
}
|
|
|
|
if ( pFmtSuggest->pwfxSrc->wFormatTag == 1 )
|
|
{
|
|
/* Compressor */
|
|
if ( pFmtSuggest->cbwfxDst < (sizeof(WAVEFORMATEX)+sizeof(WORD)) )
|
|
return MMSYSERR_INVALPARAM;
|
|
if ( pFmtSuggest->pwfxSrc->wBitsPerSample != 16 )
|
|
return ACMERR_NOTPOSSIBLE;
|
|
|
|
if ( fdwSuggest & ACM_FORMATSUGGESTF_WFORMATTAG )
|
|
{
|
|
if ( pFmtSuggest->pwfxDst->wFormatTag != 0x11 )
|
|
return ACMERR_NOTPOSSIBLE;
|
|
fdwSuggest &= ~ACM_FORMATSUGGESTF_WFORMATTAG;
|
|
}
|
|
|
|
if ( fdwSuggest & ACM_FORMATSUGGESTF_WBITSPERSAMPLE )
|
|
{
|
|
if ( pFmtSuggest->pwfxDst->wBitsPerSample != 4 )
|
|
return ACMERR_NOTPOSSIBLE;
|
|
fdwSuggest &= ~ACM_FORMATSUGGESTF_WFORMATTAG;
|
|
}
|
|
|
|
if ( fdwSuggest != 0 )
|
|
return MMSYSERR_INVALFLAG;
|
|
|
|
if ( !(fdwSuggest & ACM_FORMATSUGGESTF_WFORMATTAG) )
|
|
pFmtSuggest->pwfxDst->wFormatTag = 0x11;
|
|
pFmtSuggest->pwfxDst->nChannels = pFmtSuggest->pwfxSrc->nChannels;
|
|
pFmtSuggest->pwfxDst->nSamplesPerSec = pFmtSuggest->pwfxSrc->nSamplesPerSec;
|
|
pFmtSuggest->pwfxDst->nAvgBytesPerSec = 0; /* FIXME */
|
|
pFmtSuggest->pwfxDst->nBlockAlign = 0; /* FIXME */
|
|
pFmtSuggest->pwfxDst->wBitsPerSample = 4;
|
|
pFmtSuggest->pwfxDst->cbSize = 2;
|
|
|
|
FIXME( "no compressor" );
|
|
return ACMERR_NOTPOSSIBLE;
|
|
}
|
|
else
|
|
{
|
|
/* Decompressor */
|
|
if ( pFmtSuggest->cbwfxSrc < (sizeof(WAVEFORMATEX)+sizeof(WORD)) )
|
|
return MMSYSERR_INVALPARAM;
|
|
if ( pFmtSuggest->pwfxSrc->wFormatTag != 0x11 )
|
|
return ACMERR_NOTPOSSIBLE;
|
|
if ( pFmtSuggest->pwfxSrc->wBitsPerSample != 4 )
|
|
return ACMERR_NOTPOSSIBLE;
|
|
|
|
if ( fdwSuggest & ACM_FORMATSUGGESTF_WFORMATTAG )
|
|
{
|
|
if ( pFmtSuggest->pwfxDst->wFormatTag != 1 )
|
|
return ACMERR_NOTPOSSIBLE;
|
|
fdwSuggest &= ~ACM_FORMATSUGGESTF_WFORMATTAG;
|
|
}
|
|
|
|
if ( fdwSuggest & ACM_FORMATSUGGESTF_WBITSPERSAMPLE )
|
|
{
|
|
if ( pFmtSuggest->pwfxDst->wBitsPerSample != 16 )
|
|
return ACMERR_NOTPOSSIBLE;
|
|
fdwSuggest &= ~ACM_FORMATSUGGESTF_WFORMATTAG;
|
|
}
|
|
|
|
if ( fdwSuggest != 0 )
|
|
return MMSYSERR_INVALFLAG;
|
|
|
|
pFmtSuggest->pwfxDst->wFormatTag = 1;
|
|
pFmtSuggest->pwfxDst->nChannels = pFmtSuggest->pwfxSrc->nChannels;
|
|
pFmtSuggest->pwfxDst->nSamplesPerSec = pFmtSuggest->pwfxSrc->nSamplesPerSec;
|
|
pFmtSuggest->pwfxDst->nAvgBytesPerSec = pFmtSuggest->pwfxSrc->nSamplesPerSec * pFmtSuggest->pwfxSrc->nChannels * 2;
|
|
pFmtSuggest->pwfxDst->nBlockAlign = pFmtSuggest->pwfxSrc->nChannels * 2;
|
|
pFmtSuggest->pwfxDst->wBitsPerSample = 16;
|
|
}
|
|
|
|
return MMSYSERR_NOERROR;
|
|
}
|
|
|
|
static LONG Codec_FilterTagDetails( CodecImpl* This, ACMFILTERTAGDETAILSW* pFilterTagDetails, DWORD dwFlags )
|
|
{
|
|
/* This is a codec driver. */
|
|
return MMSYSERR_NOTSUPPORTED;
|
|
}
|
|
|
|
static LONG Codec_FilterDetails( CodecImpl* This, ACMFILTERDETAILSW* pFilterDetails, DWORD dwFlags )
|
|
{
|
|
/* This is a codec driver. */
|
|
return MMSYSERR_NOTSUPPORTED;
|
|
}
|
|
|
|
static LONG Codec_StreamOpen( CodecImpl* This, ACMDRVSTREAMINSTANCE* pStreamInst )
|
|
{
|
|
enum CodecType codectype = CodecType_Invalid;
|
|
|
|
if ( pStreamInst->cbStruct != sizeof(ACMDRVSTREAMINSTANCE) )
|
|
{
|
|
TRACE("invalid size of struct\n");
|
|
return MMSYSERR_INVALPARAM;
|
|
}
|
|
|
|
if ( pStreamInst->fdwOpen & (~(ACM_STREAMOPENF_ASYNC|ACM_STREAMOPENF_NONREALTIME|ACM_STREAMOPENF_QUERY|CALLBACK_EVENT|CALLBACK_FUNCTION|CALLBACK_WINDOW)) )
|
|
{
|
|
TRACE("unknown flags\n");
|
|
return MMSYSERR_INVALFLAG;
|
|
}
|
|
|
|
/* No support for async operations. */
|
|
if ( pStreamInst->fdwOpen & ACM_STREAMOPENF_ASYNC )
|
|
return MMSYSERR_INVALFLAG;
|
|
|
|
/* This is a codec driver. */
|
|
if ( pStreamInst->pwfxSrc->nChannels != pStreamInst->pwfxDst->nChannels || pStreamInst->pwfxSrc->nSamplesPerSec != pStreamInst->pwfxDst->nSamplesPerSec )
|
|
return ACMERR_NOTPOSSIBLE;
|
|
if ( pStreamInst->pwfltr != NULL )
|
|
return ACMERR_NOTPOSSIBLE;
|
|
|
|
if ( pStreamInst->pwfxSrc->wFormatTag == 1 )
|
|
{
|
|
if ( pStreamInst->pwfxSrc->wBitsPerSample != 16 )
|
|
return ACMERR_NOTPOSSIBLE;
|
|
if ( pStreamInst->pwfxDst->wBitsPerSample != 4 )
|
|
return ACMERR_NOTPOSSIBLE;
|
|
|
|
/* Queried as a compressor */
|
|
FIXME( "Compressor is not implemented now\n" );
|
|
return ACMERR_NOTPOSSIBLE;
|
|
}
|
|
else
|
|
if ( pStreamInst->pwfxDst->wFormatTag == 1 )
|
|
{
|
|
if ( pStreamInst->pwfxDst->wBitsPerSample != 16 )
|
|
return ACMERR_NOTPOSSIBLE;
|
|
if ( pStreamInst->pwfxSrc->wBitsPerSample != 4 )
|
|
return ACMERR_NOTPOSSIBLE;
|
|
|
|
switch ( pStreamInst->pwfxSrc->wFormatTag )
|
|
{
|
|
case 0x11: /* IMA ADPCM */
|
|
TRACE( "IMG ADPCM deompressor\n" );
|
|
codectype = CodecType_DecIMAADPCM;
|
|
break;
|
|
default:
|
|
return ACMERR_NOTPOSSIBLE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return ACMERR_NOTPOSSIBLE;
|
|
}
|
|
|
|
if ( pStreamInst->fdwOpen & ACM_STREAMOPENF_QUERY )
|
|
return MMSYSERR_NOERROR;
|
|
|
|
pStreamInst->dwDriver = (DWORD)codectype;
|
|
|
|
return MMSYSERR_NOERROR;
|
|
}
|
|
|
|
static LONG Codec_StreamClose( CodecImpl* This, ACMDRVSTREAMINSTANCE* pStreamInst )
|
|
{
|
|
return MMSYSERR_NOERROR;
|
|
}
|
|
|
|
static LONG Codec_StreamSize( CodecImpl* This, ACMDRVSTREAMINSTANCE* pStreamInst, ACMDRVSTREAMSIZE* pStreamSize )
|
|
{
|
|
enum CodecType codectype;
|
|
LONG res;
|
|
|
|
if ( pStreamSize->cbStruct != sizeof(ACMDRVSTREAMSIZE) )
|
|
return MMSYSERR_INVALPARAM;
|
|
|
|
codectype = (enum CodecType)pStreamInst->dwDriver;
|
|
|
|
res = MMSYSERR_NOERROR;
|
|
FIXME("()\n");
|
|
switch ( codectype )
|
|
{
|
|
case CodecType_EncIMAADPCM:
|
|
if ( pStreamSize->fdwSize == ACM_STREAMSIZEF_SOURCE )
|
|
pStreamSize->cbDstLength = 64 + (pStreamSize->cbSrcLength >> 2);
|
|
else
|
|
if ( pStreamSize->fdwSize == ACM_STREAMSIZEF_DESTINATION )
|
|
pStreamSize->cbSrcLength = pStreamSize->cbDstLength << 2;
|
|
else
|
|
res = MMSYSERR_INVALFLAG;
|
|
break;
|
|
case CodecType_DecIMAADPCM:
|
|
if ( pStreamSize->fdwSize == ACM_STREAMSIZEF_SOURCE )
|
|
pStreamSize->cbDstLength = pStreamSize->cbSrcLength << 2;
|
|
else
|
|
if ( pStreamSize->fdwSize == ACM_STREAMSIZEF_DESTINATION )
|
|
pStreamSize->cbSrcLength = 64 + (pStreamSize->cbDstLength >> 2);
|
|
else
|
|
res = MMSYSERR_INVALFLAG;
|
|
break;
|
|
default:
|
|
ERR( "CodecType_Invalid\n" );
|
|
res = MMSYSERR_NOTSUPPORTED;
|
|
break;
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
static LONG Codec_StreamConvert( CodecImpl* This, ACMDRVSTREAMINSTANCE* pStreamInst, ACMDRVSTREAMHEADER* pStreamHdr )
|
|
{
|
|
enum CodecType codectype;
|
|
LONG res;
|
|
|
|
codectype = (enum CodecType)pStreamInst->dwDriver;
|
|
|
|
res = MMSYSERR_NOTSUPPORTED;
|
|
switch ( codectype )
|
|
{
|
|
case CodecType_EncIMAADPCM:
|
|
FIXME( "CodecType_EncIMAADPCM\n" );
|
|
break;
|
|
case CodecType_DecIMAADPCM:
|
|
TRACE( "CodecType_DecIMAADPCM\n" );
|
|
res = IMAADPCM32_Decode( pStreamInst->pwfxSrc->nChannels, pStreamInst->pwfxSrc->nBlockAlign, *(WORD*)(((BYTE*)pStreamInst->pwfxSrc) + sizeof(WAVEFORMATEX)), pStreamHdr->pbDst, pStreamHdr->cbDstLength, &pStreamHdr->cbDstLengthUsed, pStreamHdr->pbSrc, pStreamHdr->cbSrcLength, &pStreamHdr->cbSrcLengthUsed );
|
|
break;
|
|
default:
|
|
ERR( "CodecType_Invalid\n" );
|
|
break;
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
static LONG Codec_StreamReset( CodecImpl* This, ACMDRVSTREAMINSTANCE* pStreamInst, DWORD dwFlags )
|
|
{
|
|
return MMSYSERR_NOTSUPPORTED;
|
|
}
|
|
|
|
static LONG Codec_StreamPrepare( CodecImpl* This, ACMDRVSTREAMINSTANCE* pStreamInst, ACMDRVSTREAMHEADER* pStreamHdr )
|
|
{
|
|
return MMSYSERR_NOTSUPPORTED;
|
|
}
|
|
|
|
static LONG Codec_StreamUnprepare( CodecImpl* This, ACMDRVSTREAMINSTANCE* pStreamInst, ACMDRVSTREAMHEADER* pStreamHdr )
|
|
{
|
|
return MMSYSERR_NOTSUPPORTED;
|
|
}
|
|
|
|
|
|
|
|
/***********************************************************************/
|
|
|
|
static CodecImpl* Codec_AllocDriver( void )
|
|
{
|
|
CodecImpl* This;
|
|
|
|
This = HeapAlloc( GetProcessHeap(), 0, sizeof(CodecImpl) );
|
|
if ( This == NULL )
|
|
return NULL;
|
|
ZeroMemory( This, sizeof(CodecImpl) );
|
|
|
|
/* initialize members. */
|
|
|
|
return This;
|
|
}
|
|
|
|
static void Codec_Close( CodecImpl* This )
|
|
{
|
|
|
|
HeapFree( GetProcessHeap(), 0, This );
|
|
}
|
|
|
|
|
|
|
|
/***********************************************************************/
|
|
|
|
LONG WINAPI IMAADP32_DriverProc(
|
|
DWORD dwDriverId, HDRVR hdrvr, UINT msg, LONG lParam1, LONG lParam2 )
|
|
{
|
|
TRACE( "DriverProc(%08lx,%08x,%08x,%08lx,%08lx)\n",
|
|
dwDriverId, hdrvr, msg, lParam1, lParam2 );
|
|
|
|
switch ( msg )
|
|
{
|
|
case DRV_LOAD:
|
|
TRACE("DRV_LOAD\n");
|
|
return TRUE;
|
|
case DRV_FREE:
|
|
TRACE("DRV_FREE\n");
|
|
return TRUE;
|
|
case DRV_OPEN:
|
|
TRACE("DRV_OPEN\n");
|
|
return (LONG)Codec_AllocDriver();
|
|
case DRV_CLOSE:
|
|
TRACE("DRV_CLOSE\n");
|
|
Codec_Close( (CodecImpl*)dwDriverId );
|
|
return TRUE;
|
|
case DRV_ENABLE:
|
|
TRACE("DRV_ENABLE\n");
|
|
return TRUE;
|
|
case DRV_DISABLE:
|
|
TRACE("DRV_DISABLE\n");
|
|
return TRUE;
|
|
case DRV_QUERYCONFIGURE:
|
|
TRACE("DRV_QUERYCONFIGURE\n");
|
|
return Codec_DrvQueryConfigure( (CodecImpl*)dwDriverId );
|
|
case DRV_CONFIGURE:
|
|
TRACE("DRV_CONFIGURE\n");
|
|
return Codec_DrvConfigure( (CodecImpl*)dwDriverId,
|
|
(HWND)lParam1, (DRVCONFIGINFO*)lParam2 );
|
|
case DRV_INSTALL:
|
|
TRACE("DRV_INSTALL\n");
|
|
return DRVCNF_OK;
|
|
case DRV_REMOVE:
|
|
TRACE("DRV_REMOVE\n");
|
|
return 0;
|
|
case DRV_POWER:
|
|
TRACE("DRV_POWER\n");
|
|
return TRUE;
|
|
|
|
case ACMDM_DRIVER_NOTIFY:
|
|
return MMSYSERR_NOERROR;
|
|
case ACMDM_DRIVER_DETAILS:
|
|
return Codec_DriverDetails((ACMDRIVERDETAILSW*)lParam1);
|
|
case ACMDM_DRIVER_ABOUT:
|
|
TRACE("ACMDM_DRIVER_ABOUT\n");
|
|
return (lParam1 == -1) ? Codec_QueryAbout() : Codec_About( (HWND)lParam1 );
|
|
|
|
case ACMDM_HARDWARE_WAVE_CAPS_INPUT:
|
|
return MMSYSERR_NOTSUPPORTED;
|
|
case ACMDM_HARDWARE_WAVE_CAPS_OUTPUT:
|
|
return MMSYSERR_NOTSUPPORTED;
|
|
|
|
case ACMDM_FORMATTAG_DETAILS:
|
|
return Codec_FormatTagDetails( (CodecImpl*)dwDriverId, (ACMFORMATTAGDETAILSW*)lParam1, (DWORD)lParam2 );
|
|
case ACMDM_FORMAT_DETAILS:
|
|
return Codec_FormatDetails( (CodecImpl*)dwDriverId, (ACMFORMATDETAILSW*)lParam1, (DWORD)lParam2 );
|
|
case ACMDM_FORMAT_SUGGEST:
|
|
return Codec_FormatSuggest( (CodecImpl*)dwDriverId, (ACMDRVFORMATSUGGEST*)lParam1 );
|
|
|
|
case ACMDM_FILTERTAG_DETAILS:
|
|
return Codec_FilterTagDetails( (CodecImpl*)dwDriverId, (ACMFILTERTAGDETAILSW*)lParam1, (DWORD)lParam2 );
|
|
case ACMDM_FILTER_DETAILS:
|
|
return Codec_FilterDetails( (CodecImpl*)dwDriverId, (ACMFILTERDETAILSW*)lParam1, (DWORD)lParam2 );
|
|
|
|
case ACMDM_STREAM_OPEN:
|
|
return Codec_StreamOpen( (CodecImpl*)dwDriverId, (ACMDRVSTREAMINSTANCE*)lParam1 );
|
|
case ACMDM_STREAM_CLOSE:
|
|
return Codec_StreamClose( (CodecImpl*)dwDriverId, (ACMDRVSTREAMINSTANCE*)lParam1 );
|
|
case ACMDM_STREAM_SIZE:
|
|
return Codec_StreamSize( (CodecImpl*)dwDriverId, (ACMDRVSTREAMINSTANCE*)lParam1, (ACMDRVSTREAMSIZE*)lParam2 );
|
|
case ACMDM_STREAM_CONVERT:
|
|
return Codec_StreamConvert( (CodecImpl*)dwDriverId, (ACMDRVSTREAMINSTANCE*)lParam1, (ACMDRVSTREAMHEADER*)lParam2 );
|
|
case ACMDM_STREAM_RESET:
|
|
return Codec_StreamReset( (CodecImpl*)dwDriverId, (ACMDRVSTREAMINSTANCE*)lParam1, (DWORD)lParam2 );
|
|
case ACMDM_STREAM_PREPARE:
|
|
return Codec_StreamPrepare( (CodecImpl*)dwDriverId, (ACMDRVSTREAMINSTANCE*)lParam1, (ACMDRVSTREAMHEADER*)lParam2 );
|
|
case ACMDM_STREAM_UNPREPARE:
|
|
return Codec_StreamUnprepare( (CodecImpl*)dwDriverId, (ACMDRVSTREAMINSTANCE*)lParam1, (ACMDRVSTREAMHEADER*)lParam2 );
|
|
|
|
}
|
|
|
|
return DefDriverProc( dwDriverId, hdrvr, msg, lParam1, lParam2 );
|
|
}
|
|
|
|
/***********************************************************************/
|
|
|
|
BOOL WINAPI IMAADP32_DllMain( HINSTANCE hInst, DWORD dwReason, LPVOID lpvReserved )
|
|
{
|
|
TRACE( "(%08x,%08lx,%p)\n",hInst,dwReason,lpvReserved );
|
|
|
|
return TRUE;
|
|
}
|