Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenmpegl3.c
Go to the documentation of this file.
00001 /* 00002 * MPEG Layer 3 handling 00003 * 00004 * Copyright (C) 2002 Eric Pouech 00005 * Copyright (C) 2009 CodeWeavers, Aric Stewart 00006 * Copyright (C) 2010 Kristofer Henriksson 00007 * 00008 * 00009 * This library is free software; you can redistribute it and/or 00010 * modify it under the terms of the GNU Lesser General Public 00011 * License as published by the Free Software Foundation; either 00012 * version 2.1 of the License, or (at your option) any later version. 00013 * 00014 * This library is distributed in the hope that it will be useful, 00015 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00017 * Lesser General Public License for more details. 00018 * 00019 * You should have received a copy of the GNU Lesser General Public 00020 * License along with this library; if not, write to the Free Software 00021 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 00022 */ 00023 00024 #include "config.h" 00025 #include "wine/port.h" 00026 00027 #include <assert.h> 00028 #include <stdarg.h> 00029 #include <string.h> 00030 00031 #ifdef HAVE_MPG123_H 00032 # include <mpg123.h> 00033 #else 00034 # ifdef HAVE_COREAUDIO_COREAUDIO_H 00035 # include <CoreFoundation/CoreFoundation.h> 00036 # include <CoreAudio/CoreAudio.h> 00037 # endif 00038 # ifdef HAVE_AUDIOTOOLBOX_AUDIOCONVERTER_H 00039 # include <AudioToolbox/AudioConverter.h> 00040 # endif 00041 #endif 00042 00043 #include "windef.h" 00044 #include "winbase.h" 00045 #include "wingdi.h" 00046 #include "winuser.h" 00047 #include "winnls.h" 00048 #include "mmsystem.h" 00049 #include "mmreg.h" 00050 #include "msacm.h" 00051 #include "msacmdrv.h" 00052 #include "wine/debug.h" 00053 00054 WINE_DEFAULT_DEBUG_CHANNEL(mpeg3); 00055 00056 /* table to list all supported formats... those are the basic ones. this 00057 * also helps given a unique index to each of the supported formats 00058 */ 00059 typedef struct 00060 { 00061 int nChannels; 00062 int nBits; 00063 int rate; 00064 } Format; 00065 00066 static const Format PCM_Formats[] = 00067 { 00068 {1, 8, 8000}, {2, 8, 8000}, {1, 16, 8000}, {2, 16, 8000}, 00069 {1, 8, 11025}, {2, 8, 11025}, {1, 16, 11025}, {2, 16, 11025}, 00070 {1, 8, 12000}, {2, 8, 12000}, {1, 16, 12000}, {2, 16, 12000}, 00071 {1, 8, 16000}, {2, 8, 16000}, {1, 16, 16000}, {2, 16, 16000}, 00072 {1, 8, 22050}, {2, 8, 22050}, {1, 16, 22050}, {2, 16, 22050}, 00073 {1, 8, 24000}, {2, 8, 24000}, {1, 16, 24000}, {2, 16, 24000}, 00074 {1, 8, 32000}, {2, 8, 32000}, {1, 16, 32000}, {2, 16, 32000}, 00075 {1, 8, 44100}, {2, 8, 44100}, {1, 16, 44100}, {2, 16, 44100}, 00076 {1, 8, 48000}, {2, 8, 48000}, {1, 16, 48000}, {2, 16, 48000} 00077 }; 00078 00079 static const Format MPEG3_Formats[] = 00080 { 00081 {1, 0, 8000}, {2, 0, 8000}, 00082 {1, 0, 11025}, {2, 0, 11025}, 00083 {1, 0, 12000}, {2, 0, 12000}, 00084 {1, 0, 16000}, {2, 0, 16000}, 00085 {1, 0, 22050}, {2, 0, 22050}, 00086 {1, 0, 24000}, {2, 0, 24000}, 00087 {1, 0, 32000}, {2, 0, 32000}, 00088 {1, 0, 44100}, {2, 0, 44100}, 00089 {1, 0, 48000}, {2, 0, 48000} 00090 }; 00091 00092 #define NUM_PCM_FORMATS (sizeof(PCM_Formats) / sizeof(PCM_Formats[0])) 00093 #define NUM_MPEG3_FORMATS (sizeof(MPEG3_Formats) / sizeof(MPEG3_Formats[0])) 00094 00095 /*********************************************************************** 00096 * MPEG3_GetFormatIndex 00097 */ 00098 static DWORD MPEG3_GetFormatIndex(LPWAVEFORMATEX wfx) 00099 { 00100 int i, hi; 00101 const Format *fmts; 00102 00103 switch (wfx->wFormatTag) 00104 { 00105 case WAVE_FORMAT_PCM: 00106 hi = NUM_PCM_FORMATS; 00107 fmts = PCM_Formats; 00108 break; 00109 case WAVE_FORMAT_MPEG: 00110 case WAVE_FORMAT_MPEGLAYER3: 00111 hi = NUM_MPEG3_FORMATS; 00112 fmts = MPEG3_Formats; 00113 break; 00114 default: 00115 return 0xFFFFFFFF; 00116 } 00117 00118 for (i = 0; i < hi; i++) 00119 { 00120 if (wfx->nChannels == fmts[i].nChannels && 00121 wfx->nSamplesPerSec == fmts[i].rate && 00122 (wfx->wBitsPerSample == fmts[i].nBits || !fmts[i].nBits)) 00123 return i; 00124 } 00125 00126 return 0xFFFFFFFF; 00127 } 00128 00129 #ifdef HAVE_MPG123_H 00130 00131 typedef struct tagAcmMpeg3Data 00132 { 00133 void (*convert)(PACMDRVSTREAMINSTANCE adsi, 00134 const unsigned char*, LPDWORD, unsigned char*, LPDWORD); 00135 mpg123_handle *mh; 00136 } AcmMpeg3Data; 00137 00138 /*********************************************************************** 00139 * MPEG3_drvOpen 00140 */ 00141 static LRESULT MPEG3_drvOpen(LPCSTR str) 00142 { 00143 mpg123_init(); 00144 return 1; 00145 } 00146 00147 /*********************************************************************** 00148 * MPEG3_drvClose 00149 */ 00150 static LRESULT MPEG3_drvClose(DWORD_PTR dwDevID) 00151 { 00152 mpg123_exit(); 00153 return 1; 00154 } 00155 00156 00157 static void mp3_horse(PACMDRVSTREAMINSTANCE adsi, 00158 const unsigned char* src, LPDWORD nsrc, 00159 unsigned char* dst, LPDWORD ndst) 00160 { 00161 AcmMpeg3Data* amd = (AcmMpeg3Data*)adsi->dwDriver; 00162 int ret; 00163 size_t size; 00164 DWORD dpos = 0; 00165 00166 00167 if (*nsrc > 0) 00168 { 00169 ret = mpg123_feed(amd->mh, src, *nsrc); 00170 if (ret != MPG123_OK) 00171 { 00172 ERR("Error feeding data\n"); 00173 *ndst = *nsrc = 0; 00174 return; 00175 } 00176 } 00177 00178 do { 00179 size = 0; 00180 ret = mpg123_read(amd->mh, dst + dpos, *ndst - dpos, &size); 00181 if (ret == MPG123_ERR) 00182 { 00183 FIXME("Error occurred during decoding!\n"); 00184 *ndst = *nsrc = 0; 00185 return; 00186 } 00187 00188 if (ret == MPG123_NEW_FORMAT) 00189 { 00190 long rate; 00191 int channels, enc; 00192 mpg123_getformat(amd->mh, &rate, &channels, &enc); 00193 TRACE("New format: %li Hz, %i channels, encoding value %i\n", rate, channels, enc); 00194 } 00195 dpos += size; 00196 if (dpos >= *ndst) break; 00197 } while (ret != MPG123_ERR && ret != MPG123_NEED_MORE); 00198 *ndst = dpos; 00199 } 00200 00201 /*********************************************************************** 00202 * MPEG3_Reset 00203 * 00204 */ 00205 static void MPEG3_Reset(PACMDRVSTREAMINSTANCE adsi, AcmMpeg3Data* aad) 00206 { 00207 mpg123_feedseek(aad->mh, 0, SEEK_SET, NULL); 00208 mpg123_close(aad->mh); 00209 mpg123_open_feed(aad->mh); 00210 } 00211 00212 /*********************************************************************** 00213 * MPEG3_StreamOpen 00214 * 00215 */ 00216 static LRESULT MPEG3_StreamOpen(PACMDRVSTREAMINSTANCE adsi) 00217 { 00218 AcmMpeg3Data* aad; 00219 int err; 00220 00221 assert(!(adsi->fdwOpen & ACM_STREAMOPENF_ASYNC)); 00222 00223 if (MPEG3_GetFormatIndex(adsi->pwfxSrc) == 0xFFFFFFFF || 00224 MPEG3_GetFormatIndex(adsi->pwfxDst) == 0xFFFFFFFF) 00225 return ACMERR_NOTPOSSIBLE; 00226 00227 aad = HeapAlloc(GetProcessHeap(), 0, sizeof(AcmMpeg3Data)); 00228 if (aad == 0) return MMSYSERR_NOMEM; 00229 00230 adsi->dwDriver = (DWORD_PTR)aad; 00231 00232 if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM && 00233 adsi->pwfxDst->wFormatTag == WAVE_FORMAT_PCM) 00234 { 00235 goto theEnd; 00236 } 00237 else if ((adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_MPEGLAYER3 || 00238 adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_MPEG) && 00239 adsi->pwfxDst->wFormatTag == WAVE_FORMAT_PCM) 00240 { 00241 /* resampling or mono <=> stereo not available 00242 * MPEG3 algo only define 16 bit per sample output 00243 */ 00244 if (adsi->pwfxSrc->nSamplesPerSec != adsi->pwfxDst->nSamplesPerSec || 00245 adsi->pwfxSrc->nChannels != adsi->pwfxDst->nChannels || 00246 adsi->pwfxDst->wBitsPerSample != 16) 00247 goto theEnd; 00248 aad->convert = mp3_horse; 00249 aad->mh = mpg123_new(NULL,&err); 00250 mpg123_open_feed(aad->mh); 00251 } 00252 /* no encoding yet 00253 else if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM && 00254 adsi->pwfxDst->wFormatTag == WAVE_FORMAT_MPEGLAYER3) 00255 */ 00256 else goto theEnd; 00257 MPEG3_Reset(adsi, aad); 00258 00259 return MMSYSERR_NOERROR; 00260 00261 theEnd: 00262 HeapFree(GetProcessHeap(), 0, aad); 00263 adsi->dwDriver = 0L; 00264 return MMSYSERR_NOTSUPPORTED; 00265 } 00266 00267 /*********************************************************************** 00268 * MPEG3_StreamClose 00269 * 00270 */ 00271 static LRESULT MPEG3_StreamClose(PACMDRVSTREAMINSTANCE adsi) 00272 { 00273 mpg123_close(((AcmMpeg3Data*)adsi->dwDriver)->mh); 00274 mpg123_delete(((AcmMpeg3Data*)adsi->dwDriver)->mh); 00275 HeapFree(GetProcessHeap(), 0, (void*)adsi->dwDriver); 00276 return MMSYSERR_NOERROR; 00277 } 00278 00279 #elif defined(HAVE_AUDIOTOOLBOX_AUDIOCONVERTER_H) 00280 00281 static const unsigned short Mp3BitRates[2][16] = 00282 { 00283 {0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 0}, 00284 {0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, 0} 00285 }; 00286 00287 static const unsigned short Mp3SampleRates[2][4] = 00288 { 00289 {44100, 48000, 32000, 0}, 00290 {22050, 24000, 16000, 0} 00291 }; 00292 00293 typedef struct tagAcmMpeg3Data 00294 { 00295 LRESULT (*convert)(PACMDRVSTREAMINSTANCE adsi, unsigned char*, 00296 LPDWORD, unsigned char*, LPDWORD); 00297 AudioConverterRef acr; 00298 AudioStreamBasicDescription in,out; 00299 00300 AudioBufferList outBuffer; 00301 AudioBuffer inBuffer; 00302 00303 SInt32 tagBytesLeft; 00304 00305 UInt32 NumberPackets; 00306 AudioStreamPacketDescription *PacketDescriptions; 00307 } AcmMpeg3Data; 00308 00309 /*********************************************************************** 00310 * MPEG3_drvOpen 00311 */ 00312 static LRESULT MPEG3_drvOpen(LPCSTR str) 00313 { 00314 return 1; 00315 } 00316 00317 /*********************************************************************** 00318 * MPEG3_drvClose 00319 */ 00320 static LRESULT MPEG3_drvClose(DWORD_PTR dwDevID) 00321 { 00322 return 1; 00323 } 00324 00325 /* 00326 When it asks for data, give it all we have. If we have no data, we assume 00327 we will in the future, so give it no packets and return an error, which 00328 signals that we will have more later. 00329 */ 00330 static OSStatus Mp3AudioConverterComplexInputDataProc( 00331 AudioConverterRef inAudioConverter, 00332 UInt32 *ioNumberDataPackets, 00333 AudioBufferList *ioData, 00334 AudioStreamPacketDescription **outDataPacketDescription, 00335 void *inUserData 00336 ) 00337 { 00338 AcmMpeg3Data *amd = (AcmMpeg3Data*)inUserData; 00339 00340 if (amd->inBuffer.mDataByteSize > 0) 00341 { 00342 *ioNumberDataPackets = amd->NumberPackets; 00343 ioData->mNumberBuffers = 1; 00344 ioData->mBuffers[0] = amd->inBuffer; 00345 amd->inBuffer.mDataByteSize = 0; 00346 if (outDataPacketDescription) 00347 *outDataPacketDescription = amd->PacketDescriptions; 00348 return noErr; 00349 } 00350 else 00351 { 00352 *ioNumberDataPackets = 0; 00353 return -74; 00354 } 00355 } 00356 00357 /* 00358 Get the length of the current frame. We need to be at the start of a 00359 frame now. The buffer must have at least the four bytes for the header. 00360 */ 00361 static SInt32 Mp3GetPacketLength(const unsigned char* src) 00362 { 00363 unsigned char mpegv; 00364 unsigned short brate, srate; 00365 unsigned int size; 00366 00367 /* 00368 Check that our position looks like an MP3 header and see which type 00369 of MP3 file we have. 00370 */ 00371 if (src[0] == 0xff && src[1] >> 1 == 0x7d) mpegv = 0; /* MPEG-1 File */ 00372 else if (src[0] == 0xff && src[1] >> 1 == 0x79) mpegv = 1; /* MPEG-2 File */ 00373 else return -1; 00374 00375 /* Fill in bit rate and sample rate. */ 00376 brate = Mp3BitRates[mpegv][(src[2] & 0xf0) >> 4]; 00377 srate = Mp3SampleRates[mpegv][(src[2] & 0xc) >> 2]; 00378 00379 /* Certain values for bit rate and sample rate are invalid. */ 00380 if (brate == 0 || srate == 0) return -1; 00381 00382 /* Compute frame size, round down */ 00383 size = 72 * (2 - mpegv) * brate * 1000 / srate; 00384 00385 /* If there is padding, add one byte */ 00386 if (src[2] & 0x2) return size + 1; 00387 else return size; 00388 } 00389 00390 /* 00391 Apple's AudioFileStream does weird things so we deal with parsing the 00392 file ourselves. It was also designed for a different use case, so this 00393 is not unexpected. We expect to have MP3 data as input (i.e. we can only 00394 deal with MPEG-1 or MPEG-2 Layer III), which simplifies parsing a bit. We 00395 understand the ID3v2 header and skip over it. Whenever we have data we 00396 want to skip at the beginning of the input, we do this by setting *ndst=0 00397 and *nsrc to the length of the unwanted data and return no error. 00398 */ 00399 static LRESULT mp3_leopard_horse(PACMDRVSTREAMINSTANCE adsi, 00400 unsigned char* src, LPDWORD nsrc, 00401 unsigned char* dst, LPDWORD ndst) 00402 { 00403 OSStatus err; 00404 UInt32 size, aspdi, synci, syncSkip; 00405 short framelen[4]; 00406 const unsigned char* psrc; 00407 AcmMpeg3Data* amd = (AcmMpeg3Data*)adsi->dwDriver; 00408 00409 TRACE("ndst %u %p <- %u %p\n", *ndst, dst, *nsrc, src); 00410 00411 TRACE("First 16 bytes to input: %s\n", wine_dbgstr_an((const char *)src, 16)); 00412 00413 /* Parse ID3 tag */ 00414 if (!memcmp(src, "ID3", 3) && amd->tagBytesLeft == -1) 00415 { 00416 amd->tagBytesLeft = (src[6] << 21) + (src[7] << 14) + (src[8] << 7) + src[9]; 00417 if (src[5] & 0x10) amd->tagBytesLeft += 20; /* There is a footer */ 00418 else amd->tagBytesLeft += 10; 00419 } 00420 00421 /* Consume the tag */ 00422 if (amd->tagBytesLeft >= (SInt32)*nsrc) 00423 { 00424 *ndst = 0; 00425 amd->tagBytesLeft -= *nsrc; 00426 00427 TRACE("All %d bytes of source data is ID3 tag\n", *nsrc); 00428 return MMSYSERR_NOERROR; 00429 } 00430 else if (amd->tagBytesLeft > 0) 00431 { 00432 src += amd->tagBytesLeft; 00433 *nsrc -= amd->tagBytesLeft; 00434 TRACE("Skipping %ld for ID3 tag\n", amd->tagBytesLeft); 00435 } 00436 00437 /* 00438 Sync to initial MP3 frame. The largest possible MP3 frame is 1440. 00439 Thus, in the first 1440 bytes we must find the beginning of 3 valid 00440 frames in a row unless we reach the end of the file first. 00441 */ 00442 syncSkip = 0; 00443 for (psrc = src; psrc <= src + *nsrc - 4 && psrc < src + 1440; psrc++) 00444 { 00445 framelen[0] = 0; 00446 for (synci = 1; 00447 synci < 4 && psrc + framelen[synci-1] < src + *nsrc - 4; 00448 synci++) 00449 { 00450 framelen[synci] = Mp3GetPacketLength(psrc + framelen[synci-1]); 00451 if (framelen[synci] == -1) 00452 { 00453 synci = 0; 00454 break; 00455 } 00456 framelen[synci] += framelen[synci-1]; 00457 } 00458 if (synci > 0) /* We synced successfully */ 00459 { 00460 if (psrc - src > 0) 00461 { 00462 syncSkip = psrc - src; 00463 src += syncSkip; 00464 *nsrc -= syncSkip; 00465 TRACE("Skipping %ld for frame sync\n", syncSkip); 00466 } 00467 break; 00468 } 00469 } 00470 00471 if (Mp3GetPacketLength(src) == -1) 00472 { 00473 *ndst = *nsrc = 0; 00474 ERR("Frame sync failed. Cannot play file.\n"); 00475 return MMSYSERR_ERROR; 00476 } 00477 00478 /* 00479 Fill in frame descriptions for all frames. We use an extra pointer 00480 to keep track of our position in the input. 00481 */ 00482 00483 amd->NumberPackets = 25; /* This is the initial array capacity */ 00484 amd->PacketDescriptions = HeapAlloc(GetProcessHeap(), 0, amd->NumberPackets * sizeof(AudioStreamPacketDescription)); 00485 if (amd->PacketDescriptions == 0) return MMSYSERR_NOMEM; 00486 00487 for (aspdi = 0, psrc = src; 00488 psrc <= src + *nsrc - 4; 00489 psrc += amd->PacketDescriptions[aspdi].mDataByteSize, aspdi++) 00490 { 00491 /* Return an error if we can't read the frame header */ 00492 if (Mp3GetPacketLength(psrc) == -1) 00493 { 00494 *ndst = *nsrc = 0; 00495 ERR("Invalid header at %p.\n", psrc); 00496 HeapFree(GetProcessHeap(), 0, amd->PacketDescriptions); 00497 return MMSYSERR_ERROR; 00498 } 00499 00500 /* If we run out of space, double size and reallocate */ 00501 if (aspdi >= amd->NumberPackets) 00502 { 00503 amd->NumberPackets *= 2; 00504 amd->PacketDescriptions = HeapReAlloc(GetProcessHeap(), 0, amd->PacketDescriptions, amd->NumberPackets * sizeof(AudioStreamPacketDescription)); 00505 if (amd->PacketDescriptions == 0) return MMSYSERR_NOMEM; 00506 } 00507 00508 /* Fill in packet data */ 00509 amd->PacketDescriptions[aspdi].mStartOffset = psrc - src; 00510 amd->PacketDescriptions[aspdi].mVariableFramesInPacket = 0; 00511 amd->PacketDescriptions[aspdi].mDataByteSize = Mp3GetPacketLength(psrc); 00512 00513 /* If this brings us past the end, the last one doesn't count */ 00514 if (psrc + amd->PacketDescriptions[aspdi].mDataByteSize > src + *nsrc) break; 00515 } 00516 00517 /* Fill in correct number of frames */ 00518 amd->NumberPackets = aspdi; 00519 00520 /* Adjust nsrc to only include full frames */ 00521 *nsrc = psrc - src; 00522 00523 amd->inBuffer.mDataByteSize = *nsrc; 00524 amd->inBuffer.mData = src; 00525 amd->inBuffer.mNumberChannels = amd->in.mChannelsPerFrame; 00526 00527 amd->outBuffer.mNumberBuffers = 1; 00528 amd->outBuffer.mBuffers[0].mDataByteSize = *ndst; 00529 amd->outBuffer.mBuffers[0].mData = dst; 00530 amd->outBuffer.mBuffers[0].mNumberChannels = amd->out.mChannelsPerFrame; 00531 00532 /* Convert the data */ 00533 size = amd->outBuffer.mBuffers[0].mDataByteSize / amd->out.mBytesPerPacket; 00534 err = AudioConverterFillComplexBuffer(amd->acr, Mp3AudioConverterComplexInputDataProc, amd, &size, &amd->outBuffer, 0); 00535 00536 HeapFree(GetProcessHeap(), 0, amd->PacketDescriptions); 00537 00538 /* Add skipped bytes back into *nsrc */ 00539 if (amd->tagBytesLeft > 0) 00540 { 00541 *nsrc += amd->tagBytesLeft; 00542 amd->tagBytesLeft = 0; 00543 } 00544 *nsrc += syncSkip; 00545 00546 if (err != noErr && err != -74) 00547 { 00548 *ndst = *nsrc = 0; 00549 ERR("Feed Error: %ld\n", err); 00550 return MMSYSERR_ERROR; 00551 } 00552 00553 *ndst = amd->outBuffer.mBuffers[0].mDataByteSize; 00554 00555 TRACE("convert %d -> %d\n", *nsrc, *ndst); 00556 00557 return MMSYSERR_NOERROR; 00558 } 00559 00560 /*********************************************************************** 00561 * MPEG3_Reset 00562 * 00563 */ 00564 static void MPEG3_Reset(PACMDRVSTREAMINSTANCE adsi, AcmMpeg3Data* aad) 00565 { 00566 AudioConverterReset(aad->acr); 00567 } 00568 00569 /*********************************************************************** 00570 * MPEG3_StreamOpen 00571 * 00572 */ 00573 static LRESULT MPEG3_StreamOpen(PACMDRVSTREAMINSTANCE adsi) 00574 { 00575 AcmMpeg3Data* aad; 00576 00577 assert(!(adsi->fdwOpen & ACM_STREAMOPENF_ASYNC)); 00578 00579 if (MPEG3_GetFormatIndex(adsi->pwfxSrc) == 0xFFFFFFFF || 00580 MPEG3_GetFormatIndex(adsi->pwfxDst) == 0xFFFFFFFF) 00581 return ACMERR_NOTPOSSIBLE; 00582 00583 aad = HeapAlloc(GetProcessHeap(), 0, sizeof(AcmMpeg3Data)); 00584 if (aad == 0) return MMSYSERR_NOMEM; 00585 00586 adsi->dwDriver = (DWORD_PTR)aad; 00587 00588 if ((adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_MPEGLAYER3 || 00589 adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_MPEG) && 00590 adsi->pwfxDst->wFormatTag == WAVE_FORMAT_PCM) 00591 { 00592 OSStatus err; 00593 00594 aad->in.mSampleRate = adsi->pwfxSrc->nSamplesPerSec; 00595 aad->out.mSampleRate = adsi->pwfxDst->nSamplesPerSec; 00596 aad->in.mBitsPerChannel = adsi->pwfxSrc->wBitsPerSample; 00597 aad->out.mBitsPerChannel = adsi->pwfxDst->wBitsPerSample; 00598 aad->in.mFormatID = kAudioFormatMPEGLayer3; 00599 aad->out.mFormatID = kAudioFormatLinearPCM; 00600 aad->in.mChannelsPerFrame = adsi->pwfxSrc->nChannels; 00601 aad->out.mChannelsPerFrame = adsi->pwfxDst->nChannels; 00602 aad->in.mFormatFlags = 0; 00603 aad->out.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger; 00604 aad->in.mBytesPerFrame = 0; 00605 aad->out.mBytesPerFrame = (aad->out.mBitsPerChannel * aad->out.mChannelsPerFrame) / 8; 00606 aad->in.mBytesPerPacket = 0; 00607 aad->out.mBytesPerPacket = aad->out.mBytesPerFrame; 00608 aad->in.mFramesPerPacket = 0; 00609 aad->out.mFramesPerPacket = 1; 00610 aad->in.mReserved = aad->out.mReserved = 0; 00611 00612 aad->tagBytesLeft = -1; 00613 00614 aad->convert = mp3_leopard_horse; 00615 00616 err = AudioConverterNew(&aad->in, &aad->out, &aad->acr); 00617 if (err != noErr) 00618 { 00619 ERR("Create failed: %ld\n", err); 00620 } 00621 else 00622 { 00623 MPEG3_Reset(adsi, aad); 00624 00625 return MMSYSERR_NOERROR; 00626 } 00627 } 00628 00629 HeapFree(GetProcessHeap(), 0, aad); 00630 adsi->dwDriver = 0; 00631 00632 return MMSYSERR_NOTSUPPORTED; 00633 } 00634 00635 /*********************************************************************** 00636 * MPEG3_StreamClose 00637 * 00638 */ 00639 static LRESULT MPEG3_StreamClose(PACMDRVSTREAMINSTANCE adsi) 00640 { 00641 AcmMpeg3Data* amd = (AcmMpeg3Data*)adsi->dwDriver; 00642 00643 AudioConverterDispose(amd->acr); 00644 00645 HeapFree(GetProcessHeap(), 0, amd); 00646 adsi->dwDriver = 0; 00647 00648 return MMSYSERR_NOERROR; 00649 } 00650 00651 #endif 00652 00653 /*********************************************************************** 00654 * MPEG3_DriverDetails 00655 * 00656 */ 00657 static LRESULT MPEG3_DriverDetails(PACMDRIVERDETAILSW add) 00658 { 00659 add->fccType = ACMDRIVERDETAILS_FCCTYPE_AUDIOCODEC; 00660 add->fccComp = ACMDRIVERDETAILS_FCCCOMP_UNDEFINED; 00661 add->wMid = 0xFF; 00662 add->wPid = 0x00; 00663 add->vdwACM = 0x01000000; 00664 add->vdwDriver = 0x01000000; 00665 add->fdwSupport = ACMDRIVERDETAILS_SUPPORTF_CODEC; 00666 add->cFormatTags = 3; /* PCM, MPEG3 */ 00667 add->cFilterTags = 0; 00668 add->hicon = NULL; 00669 MultiByteToWideChar( CP_ACP, 0, "WINE-MPEG3", -1, 00670 add->szShortName, sizeof(add->szShortName)/sizeof(WCHAR) ); 00671 MultiByteToWideChar( CP_ACP, 0, "Wine MPEG3 decoder", -1, 00672 add->szLongName, sizeof(add->szLongName)/sizeof(WCHAR) ); 00673 MultiByteToWideChar( CP_ACP, 0, "Brought to you by the Wine team...", -1, 00674 add->szCopyright, sizeof(add->szCopyright)/sizeof(WCHAR) ); 00675 MultiByteToWideChar( CP_ACP, 0, "Refer to LICENSE file", -1, 00676 add->szLicensing, sizeof(add->szLicensing)/sizeof(WCHAR) ); 00677 add->szFeatures[0] = 0; 00678 00679 return MMSYSERR_NOERROR; 00680 } 00681 00682 /*********************************************************************** 00683 * MPEG3_FormatTagDetails 00684 * 00685 */ 00686 static LRESULT MPEG3_FormatTagDetails(PACMFORMATTAGDETAILSW aftd, DWORD dwQuery) 00687 { 00688 static const WCHAR szPcm[]={'P','C','M',0}; 00689 static const WCHAR szMpeg3[]={'M','P','e','g','3',0}; 00690 static const WCHAR szMpeg[]={'M','P','e','g',0}; 00691 00692 switch (dwQuery) 00693 { 00694 case ACM_FORMATTAGDETAILSF_INDEX: 00695 if (aftd->dwFormatTagIndex > 2) return ACMERR_NOTPOSSIBLE; 00696 break; 00697 case ACM_FORMATTAGDETAILSF_LARGESTSIZE: 00698 if (aftd->dwFormatTag == WAVE_FORMAT_UNKNOWN) 00699 { 00700 aftd->dwFormatTagIndex = 2; /* WAVE_FORMAT_MPEG is biggest */ 00701 break; 00702 } 00703 /* fall thru */ 00704 case ACM_FORMATTAGDETAILSF_FORMATTAG: 00705 switch (aftd->dwFormatTag) 00706 { 00707 case WAVE_FORMAT_PCM: aftd->dwFormatTagIndex = 0; break; 00708 case WAVE_FORMAT_MPEGLAYER3: aftd->dwFormatTagIndex = 1; break; 00709 case WAVE_FORMAT_MPEG: aftd->dwFormatTagIndex = 2; break; 00710 default: return ACMERR_NOTPOSSIBLE; 00711 } 00712 break; 00713 default: 00714 WARN("Unsupported query %08x\n", dwQuery); 00715 return MMSYSERR_NOTSUPPORTED; 00716 } 00717 00718 aftd->fdwSupport = ACMDRIVERDETAILS_SUPPORTF_CODEC; 00719 switch (aftd->dwFormatTagIndex) 00720 { 00721 case 0: 00722 aftd->dwFormatTag = WAVE_FORMAT_PCM; 00723 aftd->cbFormatSize = sizeof(PCMWAVEFORMAT); 00724 aftd->cStandardFormats = NUM_PCM_FORMATS; 00725 lstrcpyW(aftd->szFormatTag, szPcm); 00726 break; 00727 case 1: 00728 aftd->dwFormatTag = WAVE_FORMAT_MPEGLAYER3; 00729 aftd->cbFormatSize = sizeof(MPEGLAYER3WAVEFORMAT); 00730 aftd->cStandardFormats = NUM_MPEG3_FORMATS; 00731 lstrcpyW(aftd->szFormatTag, szMpeg3); 00732 break; 00733 case 2: 00734 aftd->dwFormatTag = WAVE_FORMAT_MPEG; 00735 aftd->cbFormatSize = sizeof(MPEG1WAVEFORMAT); 00736 aftd->cStandardFormats = NUM_MPEG3_FORMATS; 00737 lstrcpyW(aftd->szFormatTag, szMpeg); 00738 break; 00739 } 00740 return MMSYSERR_NOERROR; 00741 } 00742 00743 static void fill_in_mp3(unsigned cbwfx, WAVEFORMATEX* wfx, unsigned bit_rate) 00744 { 00745 MPEGLAYER3WAVEFORMAT* mp3wfx = (MPEGLAYER3WAVEFORMAT*)wfx; 00746 00747 wfx->nAvgBytesPerSec = bit_rate / 8; 00748 if (cbwfx >= sizeof(WAVEFORMATEX)) 00749 wfx->cbSize = sizeof(MPEGLAYER3WAVEFORMAT) - sizeof(WAVEFORMATEX); 00750 if (cbwfx >= sizeof(MPEGLAYER3WAVEFORMAT)) 00751 { 00752 mp3wfx->wID = MPEGLAYER3_ID_MPEG; 00753 mp3wfx->fdwFlags = MPEGLAYER3_FLAG_PADDING_OFF; 00754 mp3wfx->nBlockSize = (bit_rate * 144) / wfx->nSamplesPerSec; 00755 mp3wfx->nFramesPerBlock = 1; 00756 mp3wfx->nCodecDelay = 0x0571; 00757 } 00758 } 00759 00760 static void fill_in_mpeg(unsigned cbwfx, WAVEFORMATEX* wfx, unsigned bit_rate) 00761 { 00762 MPEG1WAVEFORMAT* mp3wfx = (MPEG1WAVEFORMAT*)wfx; 00763 00764 wfx->nAvgBytesPerSec = bit_rate / 8; 00765 if (cbwfx >= sizeof(WAVEFORMATEX)) 00766 wfx->cbSize = sizeof(MPEG1WAVEFORMAT) - sizeof(WAVEFORMATEX); 00767 if (cbwfx >= sizeof(MPEG1WAVEFORMAT)) 00768 { 00769 mp3wfx->fwHeadLayer = ACM_MPEG_LAYER3; 00770 mp3wfx->dwHeadBitrate = wfx->nAvgBytesPerSec * 8; 00771 mp3wfx->fwHeadMode = ACM_MPEG_JOINTSTEREO; 00772 mp3wfx->fwHeadModeExt = 0xf; 00773 mp3wfx->wHeadEmphasis = 1; 00774 mp3wfx->fwHeadFlags = ACM_MPEG_ID_MPEG1; 00775 } 00776 } 00777 00778 /*********************************************************************** 00779 * MPEG3_FormatDetails 00780 * 00781 */ 00782 static LRESULT MPEG3_FormatDetails(PACMFORMATDETAILSW afd, DWORD dwQuery) 00783 { 00784 switch (dwQuery) 00785 { 00786 case ACM_FORMATDETAILSF_FORMAT: 00787 if (MPEG3_GetFormatIndex(afd->pwfx) == 0xFFFFFFFF) return ACMERR_NOTPOSSIBLE; 00788 break; 00789 case ACM_FORMATDETAILSF_INDEX: 00790 afd->pwfx->wFormatTag = afd->dwFormatTag; 00791 switch (afd->dwFormatTag) 00792 { 00793 case WAVE_FORMAT_PCM: 00794 if (afd->dwFormatIndex >= NUM_PCM_FORMATS) return ACMERR_NOTPOSSIBLE; 00795 afd->pwfx->nChannels = PCM_Formats[afd->dwFormatIndex].nChannels; 00796 afd->pwfx->nSamplesPerSec = PCM_Formats[afd->dwFormatIndex].rate; 00797 afd->pwfx->wBitsPerSample = PCM_Formats[afd->dwFormatIndex].nBits; 00798 /* native MSACM uses a PCMWAVEFORMAT structure, so cbSize is not accessible 00799 * afd->pwfx->cbSize = 0; 00800 */ 00801 afd->pwfx->nBlockAlign = 00802 (afd->pwfx->nChannels * afd->pwfx->wBitsPerSample) / 8; 00803 afd->pwfx->nAvgBytesPerSec = 00804 afd->pwfx->nSamplesPerSec * afd->pwfx->nBlockAlign; 00805 break; 00806 case WAVE_FORMAT_MPEGLAYER3: 00807 case WAVE_FORMAT_MPEG: 00808 if (afd->dwFormatIndex >= NUM_MPEG3_FORMATS) return ACMERR_NOTPOSSIBLE; 00809 afd->pwfx->nChannels = MPEG3_Formats[afd->dwFormatIndex].nChannels; 00810 afd->pwfx->nSamplesPerSec = MPEG3_Formats[afd->dwFormatIndex].rate; 00811 afd->pwfx->wBitsPerSample = MPEG3_Formats[afd->dwFormatIndex].nBits; 00812 afd->pwfx->nBlockAlign = 1; 00813 if (afd->dwFormatTag == WAVE_FORMAT_MPEGLAYER3) 00814 fill_in_mp3(afd->cbwfx, afd->pwfx, 192000); 00815 else 00816 fill_in_mpeg(afd->cbwfx, afd->pwfx, 192000); 00817 break; 00818 default: 00819 WARN("Unsupported tag %08x\n", afd->dwFormatTag); 00820 return MMSYSERR_INVALPARAM; 00821 } 00822 break; 00823 default: 00824 WARN("Unsupported query %08x\n", dwQuery); 00825 return MMSYSERR_NOTSUPPORTED; 00826 } 00827 afd->fdwSupport = ACMDRIVERDETAILS_SUPPORTF_CODEC; 00828 afd->szFormat[0] = 0; /* let MSACM format this for us... */ 00829 00830 return MMSYSERR_NOERROR; 00831 } 00832 00833 /*********************************************************************** 00834 * MPEG3_FormatSuggest 00835 * 00836 */ 00837 static LRESULT MPEG3_FormatSuggest(PACMDRVFORMATSUGGEST adfs) 00838 { 00839 /* some tests ... */ 00840 if (adfs->cbwfxSrc < sizeof(PCMWAVEFORMAT) || 00841 adfs->cbwfxDst < sizeof(PCMWAVEFORMAT) || 00842 MPEG3_GetFormatIndex(adfs->pwfxSrc) == 0xFFFFFFFF) return ACMERR_NOTPOSSIBLE; 00843 /* FIXME: should do those tests against the real size (according to format tag */ 00844 00845 /* If no suggestion for destination, then copy source value */ 00846 if (!(adfs->fdwSuggest & ACM_FORMATSUGGESTF_NCHANNELS)) 00847 adfs->pwfxDst->nChannels = adfs->pwfxSrc->nChannels; 00848 if (!(adfs->fdwSuggest & ACM_FORMATSUGGESTF_NSAMPLESPERSEC)) 00849 adfs->pwfxDst->nSamplesPerSec = adfs->pwfxSrc->nSamplesPerSec; 00850 00851 if (!(adfs->fdwSuggest & ACM_FORMATSUGGESTF_WBITSPERSAMPLE)) 00852 { 00853 if (adfs->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM) 00854 adfs->pwfxDst->wBitsPerSample = 4; 00855 else 00856 adfs->pwfxDst->wBitsPerSample = 16; 00857 } 00858 if (!(adfs->fdwSuggest & ACM_FORMATSUGGESTF_WFORMATTAG)) 00859 { 00860 if (adfs->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM) 00861 adfs->pwfxDst->wFormatTag = WAVE_FORMAT_MPEGLAYER3; 00862 else 00863 adfs->pwfxDst->wFormatTag = WAVE_FORMAT_PCM; 00864 } 00865 00866 /* check if result is ok */ 00867 if (MPEG3_GetFormatIndex(adfs->pwfxDst) == 0xFFFFFFFF) return ACMERR_NOTPOSSIBLE; 00868 00869 /* recompute other values */ 00870 switch (adfs->pwfxDst->wFormatTag) 00871 { 00872 case WAVE_FORMAT_PCM: 00873 adfs->pwfxDst->nBlockAlign = (adfs->pwfxDst->nChannels * adfs->pwfxDst->wBitsPerSample) / 8; 00874 adfs->pwfxDst->nAvgBytesPerSec = adfs->pwfxDst->nSamplesPerSec * adfs->pwfxDst->nBlockAlign; 00875 break; 00876 case WAVE_FORMAT_MPEG: 00877 adfs->pwfxDst->nBlockAlign = 1; 00878 fill_in_mpeg(adfs->cbwfxDst, adfs->pwfxDst, 192000); 00879 break; 00880 case WAVE_FORMAT_MPEGLAYER3: 00881 adfs->pwfxDst->nBlockAlign = 1; 00882 fill_in_mp3(adfs->cbwfxDst, adfs->pwfxDst, 192000); 00883 break; 00884 default: 00885 FIXME("\n"); 00886 break; 00887 } 00888 00889 return MMSYSERR_NOERROR; 00890 } 00891 00892 /*********************************************************************** 00893 * MPEG3_StreamSize 00894 * 00895 */ 00896 static LRESULT MPEG3_StreamSize(PACMDRVSTREAMINSTANCE adsi, PACMDRVSTREAMSIZE adss) 00897 { 00898 DWORD nblocks; 00899 00900 switch (adss->fdwSize) 00901 { 00902 case ACM_STREAMSIZEF_DESTINATION: 00903 /* cbDstLength => cbSrcLength */ 00904 if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM && 00905 (adsi->pwfxDst->wFormatTag == WAVE_FORMAT_MPEGLAYER3 || 00906 adsi->pwfxDst->wFormatTag == WAVE_FORMAT_MPEG)) 00907 { 00908 nblocks = (adss->cbDstLength - 3000) / (DWORD)(adsi->pwfxDst->nAvgBytesPerSec * 1152 / adsi->pwfxDst->nSamplesPerSec + 0.5); 00909 if (nblocks == 0) 00910 return ACMERR_NOTPOSSIBLE; 00911 adss->cbSrcLength = nblocks * 1152 * adsi->pwfxSrc->nBlockAlign; 00912 } 00913 else if ((adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_MPEGLAYER3 || 00914 adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_MPEG) && 00915 adsi->pwfxDst->wFormatTag == WAVE_FORMAT_PCM) 00916 { 00917 nblocks = adss->cbDstLength / (adsi->pwfxDst->nBlockAlign * 1152); 00918 if (nblocks == 0) 00919 return ACMERR_NOTPOSSIBLE; 00920 adss->cbSrcLength = nblocks * (DWORD)(adsi->pwfxSrc->nAvgBytesPerSec * 1152 / adsi->pwfxSrc->nSamplesPerSec); 00921 } 00922 else 00923 { 00924 return MMSYSERR_NOTSUPPORTED; 00925 } 00926 break; 00927 case ACM_STREAMSIZEF_SOURCE: 00928 /* cbSrcLength => cbDstLength */ 00929 if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM && 00930 (adsi->pwfxDst->wFormatTag == WAVE_FORMAT_MPEGLAYER3 || 00931 adsi->pwfxDst->wFormatTag == WAVE_FORMAT_MPEG)) 00932 { 00933 nblocks = adss->cbSrcLength / (adsi->pwfxSrc->nBlockAlign * 1152); 00934 if (nblocks == 0) 00935 return ACMERR_NOTPOSSIBLE; 00936 if (adss->cbSrcLength % (DWORD)(adsi->pwfxSrc->nBlockAlign * 1152)) 00937 /* Round block count up. */ 00938 nblocks++; 00939 adss->cbDstLength = 3000 + nblocks * (DWORD)(adsi->pwfxDst->nAvgBytesPerSec * 1152 / adsi->pwfxDst->nSamplesPerSec + 0.5); 00940 } 00941 else if ((adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_MPEGLAYER3 || 00942 adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_MPEG) && 00943 adsi->pwfxDst->wFormatTag == WAVE_FORMAT_PCM) 00944 { 00945 nblocks = adss->cbSrcLength / (DWORD)(adsi->pwfxSrc->nAvgBytesPerSec * 1152 / adsi->pwfxSrc->nSamplesPerSec); 00946 if (nblocks == 0) 00947 return ACMERR_NOTPOSSIBLE; 00948 if (adss->cbSrcLength % (DWORD)(adsi->pwfxSrc->nAvgBytesPerSec * 1152 / adsi->pwfxSrc->nSamplesPerSec)) 00949 /* Round block count up. */ 00950 nblocks++; 00951 adss->cbDstLength = nblocks * 1152 * adsi->pwfxDst->nBlockAlign; 00952 } 00953 else 00954 { 00955 return MMSYSERR_NOTSUPPORTED; 00956 } 00957 break; 00958 default: 00959 WARN("Unsupported query %08x\n", adss->fdwSize); 00960 return MMSYSERR_NOTSUPPORTED; 00961 } 00962 return MMSYSERR_NOERROR; 00963 } 00964 00965 /*********************************************************************** 00966 * MPEG3_StreamConvert 00967 * 00968 */ 00969 static LRESULT MPEG3_StreamConvert(PACMDRVSTREAMINSTANCE adsi, PACMDRVSTREAMHEADER adsh) 00970 { 00971 AcmMpeg3Data* aad = (AcmMpeg3Data*)adsi->dwDriver; 00972 DWORD nsrc = adsh->cbSrcLength; 00973 DWORD ndst = adsh->cbDstLength; 00974 00975 if (adsh->fdwConvert & 00976 ~(ACM_STREAMCONVERTF_BLOCKALIGN| 00977 ACM_STREAMCONVERTF_END| 00978 ACM_STREAMCONVERTF_START)) 00979 { 00980 FIXME("Unsupported fdwConvert (%08x), ignoring it\n", adsh->fdwConvert); 00981 } 00982 /* ACM_STREAMCONVERTF_BLOCKALIGN 00983 * currently all conversions are block aligned, so do nothing for this flag 00984 * ACM_STREAMCONVERTF_END 00985 * no pending data, so do nothing for this flag 00986 */ 00987 if ((adsh->fdwConvert & ACM_STREAMCONVERTF_START)) 00988 { 00989 MPEG3_Reset(adsi, aad); 00990 } 00991 00992 aad->convert(adsi, adsh->pbSrc, &nsrc, adsh->pbDst, &ndst); 00993 adsh->cbSrcLengthUsed = nsrc; 00994 adsh->cbDstLengthUsed = ndst; 00995 00996 return MMSYSERR_NOERROR; 00997 } 00998 00999 /************************************************************************** 01000 * MPEG3_DriverProc [exported] 01001 */ 01002 LRESULT CALLBACK MPEG3_DriverProc(DWORD_PTR dwDevID, HDRVR hDriv, UINT wMsg, 01003 LPARAM dwParam1, LPARAM dwParam2) 01004 { 01005 TRACE("(%08lx %p %04x %08lx %08lx);\n", 01006 dwDevID, hDriv, wMsg, dwParam1, dwParam2); 01007 01008 switch (wMsg) 01009 { 01010 case DRV_LOAD: return 1; 01011 case DRV_FREE: return 1; 01012 case DRV_OPEN: return MPEG3_drvOpen((LPSTR)dwParam1); 01013 case DRV_CLOSE: return MPEG3_drvClose(dwDevID); 01014 case DRV_ENABLE: return 1; 01015 case DRV_DISABLE: return 1; 01016 case DRV_QUERYCONFIGURE: return 1; 01017 case DRV_CONFIGURE: MessageBoxA(0, "MPEG3 filter !", "Wine Driver", MB_OK); return 1; 01018 case DRV_INSTALL: return DRVCNF_RESTART; 01019 case DRV_REMOVE: return DRVCNF_RESTART; 01020 01021 case ACMDM_DRIVER_NOTIFY: 01022 /* no caching from other ACM drivers is done so far */ 01023 return MMSYSERR_NOERROR; 01024 01025 case ACMDM_DRIVER_DETAILS: 01026 return MPEG3_DriverDetails((PACMDRIVERDETAILSW)dwParam1); 01027 01028 case ACMDM_FORMATTAG_DETAILS: 01029 return MPEG3_FormatTagDetails((PACMFORMATTAGDETAILSW)dwParam1, dwParam2); 01030 01031 case ACMDM_FORMAT_DETAILS: 01032 return MPEG3_FormatDetails((PACMFORMATDETAILSW)dwParam1, dwParam2); 01033 01034 case ACMDM_FORMAT_SUGGEST: 01035 return MPEG3_FormatSuggest((PACMDRVFORMATSUGGEST)dwParam1); 01036 01037 case ACMDM_STREAM_OPEN: 01038 return MPEG3_StreamOpen((PACMDRVSTREAMINSTANCE)dwParam1); 01039 01040 case ACMDM_STREAM_CLOSE: 01041 return MPEG3_StreamClose((PACMDRVSTREAMINSTANCE)dwParam1); 01042 01043 case ACMDM_STREAM_SIZE: 01044 return MPEG3_StreamSize((PACMDRVSTREAMINSTANCE)dwParam1, (PACMDRVSTREAMSIZE)dwParam2); 01045 01046 case ACMDM_STREAM_CONVERT: 01047 return MPEG3_StreamConvert((PACMDRVSTREAMINSTANCE)dwParam1, (PACMDRVSTREAMHEADER)dwParam2); 01048 01049 case ACMDM_HARDWARE_WAVE_CAPS_INPUT: 01050 case ACMDM_HARDWARE_WAVE_CAPS_OUTPUT: 01051 /* this converter is not a hardware driver */ 01052 case ACMDM_FILTERTAG_DETAILS: 01053 case ACMDM_FILTER_DETAILS: 01054 /* this converter is not a filter */ 01055 case ACMDM_STREAM_RESET: 01056 /* only needed for asynchronous driver... we aren't, so just say it */ 01057 return MMSYSERR_NOTSUPPORTED; 01058 case ACMDM_STREAM_PREPARE: 01059 case ACMDM_STREAM_UNPREPARE: 01060 /* nothing special to do here... so don't do anything */ 01061 return MMSYSERR_NOERROR; 01062 01063 default: 01064 return DefDriverProc(dwDevID, hDriv, wMsg, dwParam1, dwParam2); 01065 } 01066 } Generated on Mon May 28 2012 04:26:28 for ReactOS by
1.7.6.1
|