ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

mpegl3.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 doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.