wbemprox: Implement StdRegProv.CreateKey.
[wine.git] / dlls / l3codeca.acm / mpegl3.c
blobf71aac307f717c45731b8cb99901bc84f577df2c
1 /*
2 * MPEG Layer 3 handling
4 * Copyright (C) 2002 Eric Pouech
5 * Copyright (C) 2009 CodeWeavers, Aric Stewart
6 * Copyright (C) 2010 Kristofer Henriksson
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 #include "config.h"
25 #include "wine/port.h"
27 #include <assert.h>
28 #include <stdarg.h>
29 #include <string.h>
31 #ifdef HAVE_MPG123_H
32 # include <mpg123.h>
33 #else
34 # ifdef HAVE_COREAUDIO_COREAUDIO_H
35 # include <CoreFoundation/CoreFoundation.h>
36 # include <CoreAudio/CoreAudio.h>
37 # endif
38 # ifdef HAVE_AUDIOTOOLBOX_AUDIOCONVERTER_H
39 # include <AudioToolbox/AudioConverter.h>
40 # endif
41 #endif
43 #include "windef.h"
44 #include "winbase.h"
45 #include "wingdi.h"
46 #include "winuser.h"
47 #include "winnls.h"
48 #include "mmsystem.h"
49 #include "mmreg.h"
50 #include "msacm.h"
51 #include "msacmdrv.h"
52 #include "wine/debug.h"
54 WINE_DEFAULT_DEBUG_CHANNEL(mpeg3);
56 /* table to list all supported formats... those are the basic ones. this
57 * also helps given a unique index to each of the supported formats
59 typedef struct
61 int nChannels;
62 int nBits;
63 int rate;
64 } Format;
66 static const Format PCM_Formats[] =
68 {1, 8, 8000}, {2, 8, 8000}, {1, 16, 8000}, {2, 16, 8000},
69 {1, 8, 11025}, {2, 8, 11025}, {1, 16, 11025}, {2, 16, 11025},
70 {1, 8, 12000}, {2, 8, 12000}, {1, 16, 12000}, {2, 16, 12000},
71 {1, 8, 16000}, {2, 8, 16000}, {1, 16, 16000}, {2, 16, 16000},
72 {1, 8, 22050}, {2, 8, 22050}, {1, 16, 22050}, {2, 16, 22050},
73 {1, 8, 24000}, {2, 8, 24000}, {1, 16, 24000}, {2, 16, 24000},
74 {1, 8, 32000}, {2, 8, 32000}, {1, 16, 32000}, {2, 16, 32000},
75 {1, 8, 44100}, {2, 8, 44100}, {1, 16, 44100}, {2, 16, 44100},
76 {1, 8, 48000}, {2, 8, 48000}, {1, 16, 48000}, {2, 16, 48000}
79 static const Format MPEG3_Formats[] =
81 {1, 0, 8000}, {2, 0, 8000},
82 {1, 0, 11025}, {2, 0, 11025},
83 {1, 0, 12000}, {2, 0, 12000},
84 {1, 0, 16000}, {2, 0, 16000},
85 {1, 0, 22050}, {2, 0, 22050},
86 {1, 0, 24000}, {2, 0, 24000},
87 {1, 0, 32000}, {2, 0, 32000},
88 {1, 0, 44100}, {2, 0, 44100},
89 {1, 0, 48000}, {2, 0, 48000}
92 /***********************************************************************
93 * MPEG3_GetFormatIndex
95 static DWORD MPEG3_GetFormatIndex(LPWAVEFORMATEX wfx)
97 int i, hi;
98 const Format *fmts;
100 switch (wfx->wFormatTag)
102 case WAVE_FORMAT_PCM:
103 hi = ARRAY_SIZE(PCM_Formats);
104 fmts = PCM_Formats;
105 break;
106 case WAVE_FORMAT_MPEG:
107 case WAVE_FORMAT_MPEGLAYER3:
108 hi = ARRAY_SIZE(MPEG3_Formats);
109 fmts = MPEG3_Formats;
110 break;
111 default:
112 return 0xFFFFFFFF;
115 for (i = 0; i < hi; i++)
117 if (wfx->nChannels == fmts[i].nChannels &&
118 wfx->nSamplesPerSec == fmts[i].rate &&
119 (wfx->wBitsPerSample == fmts[i].nBits || !fmts[i].nBits))
120 return i;
123 return 0xFFFFFFFF;
126 #ifdef HAVE_MPG123_H
128 typedef struct tagAcmMpeg3Data
130 void (*convert)(PACMDRVSTREAMINSTANCE adsi,
131 const unsigned char*, LPDWORD, unsigned char*, LPDWORD);
132 mpg123_handle *mh;
133 } AcmMpeg3Data;
135 /***********************************************************************
136 * MPEG3_drvOpen
138 static LRESULT MPEG3_drvOpen(LPCSTR str)
140 mpg123_init();
141 return 1;
144 /***********************************************************************
145 * MPEG3_drvClose
147 static LRESULT MPEG3_drvClose(DWORD_PTR dwDevID)
149 mpg123_exit();
150 return 1;
154 static void mp3_horse(PACMDRVSTREAMINSTANCE adsi,
155 const unsigned char* src, LPDWORD nsrc,
156 unsigned char* dst, LPDWORD ndst)
158 AcmMpeg3Data* amd = (AcmMpeg3Data*)adsi->dwDriver;
159 int ret;
160 size_t size;
161 DWORD dpos = 0;
164 if (*nsrc > 0)
166 ret = mpg123_feed(amd->mh, src, *nsrc);
167 if (ret != MPG123_OK)
169 ERR("Error feeding data\n");
170 *ndst = *nsrc = 0;
171 return;
175 do {
176 size = 0;
177 ret = mpg123_read(amd->mh, dst + dpos, *ndst - dpos, &size);
178 if (ret == MPG123_ERR)
180 FIXME("Error occurred during decoding!\n");
181 *ndst = *nsrc = 0;
182 return;
185 if (ret == MPG123_NEW_FORMAT)
187 long rate;
188 int channels, enc;
189 mpg123_getformat(amd->mh, &rate, &channels, &enc);
190 TRACE("New format: %li Hz, %i channels, encoding value %i\n", rate, channels, enc);
192 dpos += size;
193 if (dpos >= *ndst) break;
194 } while (ret != MPG123_ERR && ret != MPG123_NEED_MORE);
195 *ndst = dpos;
198 /***********************************************************************
199 * MPEG3_Reset
202 static void MPEG3_Reset(PACMDRVSTREAMINSTANCE adsi, AcmMpeg3Data* aad)
204 mpg123_feedseek(aad->mh, 0, SEEK_SET, NULL);
205 mpg123_close(aad->mh);
206 mpg123_open_feed(aad->mh);
209 /***********************************************************************
210 * MPEG3_StreamOpen
213 static LRESULT MPEG3_StreamOpen(PACMDRVSTREAMINSTANCE adsi)
215 AcmMpeg3Data* aad;
216 int err;
218 assert(!(adsi->fdwOpen & ACM_STREAMOPENF_ASYNC));
220 if (MPEG3_GetFormatIndex(adsi->pwfxSrc) == 0xFFFFFFFF ||
221 MPEG3_GetFormatIndex(adsi->pwfxDst) == 0xFFFFFFFF)
222 return ACMERR_NOTPOSSIBLE;
224 aad = HeapAlloc(GetProcessHeap(), 0, sizeof(AcmMpeg3Data));
225 if (aad == 0) return MMSYSERR_NOMEM;
227 adsi->dwDriver = (DWORD_PTR)aad;
229 if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM &&
230 adsi->pwfxDst->wFormatTag == WAVE_FORMAT_PCM)
232 goto theEnd;
234 else if ((adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_MPEGLAYER3 ||
235 adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_MPEG) &&
236 adsi->pwfxDst->wFormatTag == WAVE_FORMAT_PCM)
238 /* resampling or mono <=> stereo not available
239 * MPEG3 algo only define 16 bit per sample output
241 if (adsi->pwfxSrc->nSamplesPerSec != adsi->pwfxDst->nSamplesPerSec ||
242 adsi->pwfxSrc->nChannels != adsi->pwfxDst->nChannels ||
243 adsi->pwfxDst->wBitsPerSample != 16)
244 goto theEnd;
245 aad->convert = mp3_horse;
246 aad->mh = mpg123_new(NULL,&err);
247 mpg123_open_feed(aad->mh);
249 #if MPG123_API_VERSION >= 31 /* needed for MPG123_IGNORE_FRAMEINFO enum value */
250 /* mpg123 may find a XING header in the mp3 and use that information
251 * to ask for seeks in order to read specific frames in the file.
252 * We cannot allow that since the caller application is feeding us.
253 * This fixes problems for mp3 files encoded with LAME (bug 42361)
255 mpg123_param(aad->mh, MPG123_ADD_FLAGS, MPG123_IGNORE_INFOFRAME, 0);
256 #endif
258 else if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM &&
259 (adsi->pwfxDst->wFormatTag == WAVE_FORMAT_MPEGLAYER3 ||
260 adsi->pwfxDst->wFormatTag == WAVE_FORMAT_MPEG))
262 WARN("Encoding to MPEG is not supported\n");
263 goto theEnd;
265 else goto theEnd;
266 MPEG3_Reset(adsi, aad);
268 return MMSYSERR_NOERROR;
270 theEnd:
271 HeapFree(GetProcessHeap(), 0, aad);
272 adsi->dwDriver = 0L;
273 return MMSYSERR_NOTSUPPORTED;
276 /***********************************************************************
277 * MPEG3_StreamClose
280 static LRESULT MPEG3_StreamClose(PACMDRVSTREAMINSTANCE adsi)
282 mpg123_close(((AcmMpeg3Data*)adsi->dwDriver)->mh);
283 mpg123_delete(((AcmMpeg3Data*)adsi->dwDriver)->mh);
284 HeapFree(GetProcessHeap(), 0, (void*)adsi->dwDriver);
285 return MMSYSERR_NOERROR;
288 #elif defined(HAVE_AUDIOTOOLBOX_AUDIOCONVERTER_H)
290 static const unsigned short Mp3BitRates[2][16] =
292 {0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 0},
293 {0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, 0}
296 static const unsigned short Mp3SampleRates[2][4] =
298 {44100, 48000, 32000, 0},
299 {22050, 24000, 16000, 0}
302 typedef struct tagAcmMpeg3Data
304 LRESULT (*convert)(PACMDRVSTREAMINSTANCE adsi, unsigned char*,
305 LPDWORD, unsigned char*, LPDWORD);
306 AudioConverterRef acr;
307 AudioStreamBasicDescription in,out;
309 AudioBufferList outBuffer;
310 AudioBuffer inBuffer;
312 SInt32 tagBytesLeft;
314 UInt32 NumberPackets;
315 AudioStreamPacketDescription *PacketDescriptions;
316 } AcmMpeg3Data;
318 /***********************************************************************
319 * MPEG3_drvOpen
321 static LRESULT MPEG3_drvOpen(LPCSTR str)
323 return 1;
326 /***********************************************************************
327 * MPEG3_drvClose
329 static LRESULT MPEG3_drvClose(DWORD_PTR dwDevID)
331 return 1;
335 When it asks for data, give it all we have. If we have no data, we assume
336 we will in the future, so give it no packets and return an error, which
337 signals that we will have more later.
339 static OSStatus Mp3AudioConverterComplexInputDataProc(
340 AudioConverterRef inAudioConverter,
341 UInt32 *ioNumberDataPackets,
342 AudioBufferList *ioData,
343 AudioStreamPacketDescription **outDataPacketDescription,
344 void *inUserData
347 AcmMpeg3Data *amd = (AcmMpeg3Data*)inUserData;
349 if (amd->inBuffer.mDataByteSize > 0)
351 *ioNumberDataPackets = amd->NumberPackets;
352 ioData->mNumberBuffers = 1;
353 ioData->mBuffers[0] = amd->inBuffer;
354 amd->inBuffer.mDataByteSize = 0;
355 if (outDataPacketDescription)
356 *outDataPacketDescription = amd->PacketDescriptions;
357 return noErr;
359 else
361 *ioNumberDataPackets = 0;
362 return -74;
367 Get the length of the current frame. We need to be at the start of a
368 frame now. The buffer must have at least the four bytes for the header.
370 static SInt32 Mp3GetPacketLength(const unsigned char* src)
372 unsigned char mpegv;
373 unsigned short brate, srate;
374 unsigned int size;
377 Check that our position looks like an MP3 header and see which type
378 of MP3 file we have.
380 if (src[0] == 0xff && src[1] >> 1 == 0x7d) mpegv = 0; /* MPEG-1 File */
381 else if (src[0] == 0xff && src[1] >> 1 == 0x79) mpegv = 1; /* MPEG-2 File */
382 else return -1;
384 /* Fill in bit rate and sample rate. */
385 brate = Mp3BitRates[mpegv][(src[2] & 0xf0) >> 4];
386 srate = Mp3SampleRates[mpegv][(src[2] & 0xc) >> 2];
388 /* Certain values for bit rate and sample rate are invalid. */
389 if (brate == 0 || srate == 0) return -1;
391 /* Compute frame size, round down */
392 size = 72 * (2 - mpegv) * brate * 1000 / srate;
394 /* If there is padding, add one byte */
395 if (src[2] & 0x2) return size + 1;
396 else return size;
400 Apple's AudioFileStream does weird things so we deal with parsing the
401 file ourselves. It was also designed for a different use case, so this
402 is not unexpected. We expect to have MP3 data as input (i.e. we can only
403 deal with MPEG-1 or MPEG-2 Layer III), which simplifies parsing a bit. We
404 understand the ID3v2 header and skip over it. Whenever we have data we
405 want to skip at the beginning of the input, we do this by setting *ndst=0
406 and *nsrc to the length of the unwanted data and return no error.
408 static LRESULT mp3_leopard_horse(PACMDRVSTREAMINSTANCE adsi,
409 unsigned char* src, LPDWORD nsrc,
410 unsigned char* dst, LPDWORD ndst)
412 OSStatus err;
413 UInt32 size, aspdi, synci, syncSkip;
414 short framelen[4];
415 const unsigned char* psrc;
416 AcmMpeg3Data* amd = (AcmMpeg3Data*)adsi->dwDriver;
418 TRACE("ndst %u %p <- %u %p\n", *ndst, dst, *nsrc, src);
420 TRACE("First 16 bytes to input: %s\n", wine_dbgstr_an((const char *)src, 16));
422 /* Parse ID3 tag */
423 if (!memcmp(src, "ID3", 3) && amd->tagBytesLeft == -1)
425 amd->tagBytesLeft = (src[6] << 21) + (src[7] << 14) + (src[8] << 7) + src[9];
426 if (src[5] & 0x10) amd->tagBytesLeft += 20; /* There is a footer */
427 else amd->tagBytesLeft += 10;
430 /* Consume the tag */
431 if (amd->tagBytesLeft >= (SInt32)*nsrc)
433 *ndst = 0;
434 amd->tagBytesLeft -= *nsrc;
436 TRACE("All %d bytes of source data is ID3 tag\n", *nsrc);
437 return MMSYSERR_NOERROR;
439 else if (amd->tagBytesLeft > 0)
441 src += amd->tagBytesLeft;
442 *nsrc -= amd->tagBytesLeft;
443 TRACE("Skipping %ld for ID3 tag\n", amd->tagBytesLeft);
447 Sync to initial MP3 frame. The largest possible MP3 frame is 1440.
448 Thus, in the first 1440 bytes we must find the beginning of 3 valid
449 frames in a row unless we reach the end of the file first.
451 syncSkip = 0;
452 for (psrc = src; psrc <= src + *nsrc - 4 && psrc < src + 1440; psrc++)
454 framelen[0] = 0;
455 for (synci = 1;
456 synci < 4 && psrc + framelen[synci-1] < src + *nsrc - 4;
457 synci++)
459 framelen[synci] = Mp3GetPacketLength(psrc + framelen[synci-1]);
460 if (framelen[synci] == -1)
462 synci = 0;
463 break;
465 framelen[synci] += framelen[synci-1];
467 if (synci > 0) /* We synced successfully */
469 if (psrc - src > 0)
471 syncSkip = psrc - src;
472 src += syncSkip;
473 *nsrc -= syncSkip;
474 TRACE("Skipping %ld for frame sync\n", syncSkip);
476 break;
480 if (Mp3GetPacketLength(src) == -1)
482 *ndst = *nsrc = 0;
483 ERR("Frame sync failed. Cannot play file.\n");
484 return MMSYSERR_ERROR;
488 Fill in frame descriptions for all frames. We use an extra pointer
489 to keep track of our position in the input.
492 amd->NumberPackets = 25; /* This is the initial array capacity */
493 amd->PacketDescriptions = HeapAlloc(GetProcessHeap(), 0, amd->NumberPackets * sizeof(AudioStreamPacketDescription));
494 if (amd->PacketDescriptions == 0) return MMSYSERR_NOMEM;
496 for (aspdi = 0, psrc = src;
497 psrc <= src + *nsrc - 4;
498 psrc += amd->PacketDescriptions[aspdi].mDataByteSize, aspdi++)
500 /* Return an error if we can't read the frame header */
501 if (Mp3GetPacketLength(psrc) == -1)
503 *ndst = *nsrc = 0;
504 ERR("Invalid header at %p.\n", psrc);
505 HeapFree(GetProcessHeap(), 0, amd->PacketDescriptions);
506 return MMSYSERR_ERROR;
509 /* If we run out of space, double size and reallocate */
510 if (aspdi >= amd->NumberPackets)
512 amd->NumberPackets *= 2;
513 amd->PacketDescriptions = HeapReAlloc(GetProcessHeap(), 0, amd->PacketDescriptions, amd->NumberPackets * sizeof(AudioStreamPacketDescription));
514 if (amd->PacketDescriptions == 0) return MMSYSERR_NOMEM;
517 /* Fill in packet data */
518 amd->PacketDescriptions[aspdi].mStartOffset = psrc - src;
519 amd->PacketDescriptions[aspdi].mVariableFramesInPacket = 0;
520 amd->PacketDescriptions[aspdi].mDataByteSize = Mp3GetPacketLength(psrc);
522 /* If this brings us past the end, the last one doesn't count */
523 if (psrc + amd->PacketDescriptions[aspdi].mDataByteSize > src + *nsrc) break;
526 /* Fill in correct number of frames */
527 amd->NumberPackets = aspdi;
529 /* Adjust nsrc to only include full frames */
530 *nsrc = psrc - src;
532 amd->inBuffer.mDataByteSize = *nsrc;
533 amd->inBuffer.mData = src;
534 amd->inBuffer.mNumberChannels = amd->in.mChannelsPerFrame;
536 amd->outBuffer.mNumberBuffers = 1;
537 amd->outBuffer.mBuffers[0].mDataByteSize = *ndst;
538 amd->outBuffer.mBuffers[0].mData = dst;
539 amd->outBuffer.mBuffers[0].mNumberChannels = amd->out.mChannelsPerFrame;
541 /* Convert the data */
542 size = amd->outBuffer.mBuffers[0].mDataByteSize / amd->out.mBytesPerPacket;
543 err = AudioConverterFillComplexBuffer(amd->acr, Mp3AudioConverterComplexInputDataProc, amd, &size, &amd->outBuffer, 0);
545 HeapFree(GetProcessHeap(), 0, amd->PacketDescriptions);
547 /* Add skipped bytes back into *nsrc */
548 if (amd->tagBytesLeft > 0)
550 *nsrc += amd->tagBytesLeft;
551 amd->tagBytesLeft = 0;
553 *nsrc += syncSkip;
555 if (err != noErr && err != -74)
557 *ndst = *nsrc = 0;
558 ERR("Feed Error: %ld\n", err);
559 return MMSYSERR_ERROR;
562 *ndst = amd->outBuffer.mBuffers[0].mDataByteSize;
564 TRACE("convert %d -> %d\n", *nsrc, *ndst);
566 return MMSYSERR_NOERROR;
569 /***********************************************************************
570 * MPEG3_Reset
573 static void MPEG3_Reset(PACMDRVSTREAMINSTANCE adsi, AcmMpeg3Data* aad)
575 AudioConverterReset(aad->acr);
578 /***********************************************************************
579 * MPEG3_StreamOpen
582 static LRESULT MPEG3_StreamOpen(PACMDRVSTREAMINSTANCE adsi)
584 AcmMpeg3Data* aad;
586 assert(!(adsi->fdwOpen & ACM_STREAMOPENF_ASYNC));
588 if (MPEG3_GetFormatIndex(adsi->pwfxSrc) == 0xFFFFFFFF ||
589 MPEG3_GetFormatIndex(adsi->pwfxDst) == 0xFFFFFFFF)
590 return ACMERR_NOTPOSSIBLE;
592 aad = HeapAlloc(GetProcessHeap(), 0, sizeof(AcmMpeg3Data));
593 if (aad == 0) return MMSYSERR_NOMEM;
595 adsi->dwDriver = (DWORD_PTR)aad;
597 if ((adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_MPEGLAYER3 ||
598 adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_MPEG) &&
599 adsi->pwfxDst->wFormatTag == WAVE_FORMAT_PCM)
601 OSStatus err;
603 aad->in.mSampleRate = adsi->pwfxSrc->nSamplesPerSec;
604 aad->out.mSampleRate = adsi->pwfxDst->nSamplesPerSec;
605 aad->in.mBitsPerChannel = adsi->pwfxSrc->wBitsPerSample;
606 aad->out.mBitsPerChannel = adsi->pwfxDst->wBitsPerSample;
607 aad->in.mFormatID = kAudioFormatMPEGLayer3;
608 aad->out.mFormatID = kAudioFormatLinearPCM;
609 aad->in.mChannelsPerFrame = adsi->pwfxSrc->nChannels;
610 aad->out.mChannelsPerFrame = adsi->pwfxDst->nChannels;
611 aad->in.mFormatFlags = 0;
612 aad->out.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger;
613 aad->in.mBytesPerFrame = 0;
614 aad->out.mBytesPerFrame = (aad->out.mBitsPerChannel * aad->out.mChannelsPerFrame) / 8;
615 aad->in.mBytesPerPacket = 0;
616 aad->out.mBytesPerPacket = aad->out.mBytesPerFrame;
617 aad->in.mFramesPerPacket = 0;
618 aad->out.mFramesPerPacket = 1;
619 aad->in.mReserved = aad->out.mReserved = 0;
621 aad->tagBytesLeft = -1;
623 aad->convert = mp3_leopard_horse;
625 err = AudioConverterNew(&aad->in, &aad->out, &aad->acr);
626 if (err != noErr)
628 ERR("Create failed: %ld\n", err);
630 else
632 MPEG3_Reset(adsi, aad);
634 return MMSYSERR_NOERROR;
638 HeapFree(GetProcessHeap(), 0, aad);
639 adsi->dwDriver = 0;
641 return MMSYSERR_NOTSUPPORTED;
644 /***********************************************************************
645 * MPEG3_StreamClose
648 static LRESULT MPEG3_StreamClose(PACMDRVSTREAMINSTANCE adsi)
650 AcmMpeg3Data* amd = (AcmMpeg3Data*)adsi->dwDriver;
652 AudioConverterDispose(amd->acr);
654 HeapFree(GetProcessHeap(), 0, amd);
655 adsi->dwDriver = 0;
657 return MMSYSERR_NOERROR;
660 #endif
662 /***********************************************************************
663 * MPEG3_DriverDetails
666 static LRESULT MPEG3_DriverDetails(PACMDRIVERDETAILSW add)
668 add->fccType = ACMDRIVERDETAILS_FCCTYPE_AUDIOCODEC;
669 add->fccComp = ACMDRIVERDETAILS_FCCCOMP_UNDEFINED;
670 add->wMid = MM_FRAUNHOFER_IIS;
671 add->wPid = MM_FHGIIS_MPEGLAYER3_DECODE;
672 add->vdwACM = 0x01000000;
673 add->vdwDriver = 0x01000000;
674 add->fdwSupport = ACMDRIVERDETAILS_SUPPORTF_CODEC;
675 add->cFormatTags = 3; /* PCM, MPEG3 */
676 add->cFilterTags = 0;
677 add->hicon = NULL;
678 MultiByteToWideChar( CP_ACP, 0, "MPEG Layer-3 Codec", -1,
679 add->szShortName, sizeof(add->szShortName)/sizeof(WCHAR) );
680 MultiByteToWideChar( CP_ACP, 0, "Wine MPEG3 decoder", -1,
681 add->szLongName, sizeof(add->szLongName)/sizeof(WCHAR) );
682 MultiByteToWideChar( CP_ACP, 0, "Brought to you by the Wine team...", -1,
683 add->szCopyright, sizeof(add->szCopyright)/sizeof(WCHAR) );
684 MultiByteToWideChar( CP_ACP, 0, "Refer to LICENSE file", -1,
685 add->szLicensing, sizeof(add->szLicensing)/sizeof(WCHAR) );
686 add->szFeatures[0] = 0;
688 return MMSYSERR_NOERROR;
691 /***********************************************************************
692 * MPEG3_FormatTagDetails
695 static LRESULT MPEG3_FormatTagDetails(PACMFORMATTAGDETAILSW aftd, DWORD dwQuery)
697 static const WCHAR szPcm[]={'P','C','M',0};
698 static const WCHAR szMpeg3[]={'M','P','e','g','3',0};
699 static const WCHAR szMpeg[]={'M','P','e','g',0};
701 switch (dwQuery)
703 case ACM_FORMATTAGDETAILSF_INDEX:
704 if (aftd->dwFormatTagIndex > 2) return ACMERR_NOTPOSSIBLE;
705 break;
706 case ACM_FORMATTAGDETAILSF_LARGESTSIZE:
707 if (aftd->dwFormatTag == WAVE_FORMAT_UNKNOWN)
709 aftd->dwFormatTagIndex = 2; /* WAVE_FORMAT_MPEG is biggest */
710 break;
712 /* fall through */
713 case ACM_FORMATTAGDETAILSF_FORMATTAG:
714 switch (aftd->dwFormatTag)
716 case WAVE_FORMAT_PCM: aftd->dwFormatTagIndex = 0; break;
717 case WAVE_FORMAT_MPEGLAYER3: aftd->dwFormatTagIndex = 1; break;
718 case WAVE_FORMAT_MPEG: aftd->dwFormatTagIndex = 2; break;
719 default: return ACMERR_NOTPOSSIBLE;
721 break;
722 default:
723 WARN("Unsupported query %08x\n", dwQuery);
724 return MMSYSERR_NOTSUPPORTED;
727 aftd->fdwSupport = ACMDRIVERDETAILS_SUPPORTF_CODEC;
728 switch (aftd->dwFormatTagIndex)
730 case 0:
731 aftd->dwFormatTag = WAVE_FORMAT_PCM;
732 aftd->cbFormatSize = sizeof(PCMWAVEFORMAT);
733 aftd->cStandardFormats = ARRAY_SIZE(PCM_Formats);
734 lstrcpyW(aftd->szFormatTag, szPcm);
735 break;
736 case 1:
737 aftd->dwFormatTag = WAVE_FORMAT_MPEGLAYER3;
738 aftd->cbFormatSize = sizeof(MPEGLAYER3WAVEFORMAT);
739 aftd->cStandardFormats = 0;
740 lstrcpyW(aftd->szFormatTag, szMpeg3);
741 break;
742 case 2:
743 aftd->dwFormatTag = WAVE_FORMAT_MPEG;
744 aftd->cbFormatSize = sizeof(MPEG1WAVEFORMAT);
745 aftd->cStandardFormats = 0;
746 lstrcpyW(aftd->szFormatTag, szMpeg);
747 break;
749 return MMSYSERR_NOERROR;
752 /***********************************************************************
753 * MPEG3_FormatDetails
756 static LRESULT MPEG3_FormatDetails(PACMFORMATDETAILSW afd, DWORD dwQuery)
758 switch (dwQuery)
760 case ACM_FORMATDETAILSF_FORMAT:
761 if (MPEG3_GetFormatIndex(afd->pwfx) == 0xFFFFFFFF) return ACMERR_NOTPOSSIBLE;
762 break;
763 case ACM_FORMATDETAILSF_INDEX:
764 afd->pwfx->wFormatTag = afd->dwFormatTag;
765 switch (afd->dwFormatTag)
767 case WAVE_FORMAT_PCM:
768 if (afd->dwFormatIndex >= ARRAY_SIZE(PCM_Formats)) return ACMERR_NOTPOSSIBLE;
769 afd->pwfx->nChannels = PCM_Formats[afd->dwFormatIndex].nChannels;
770 afd->pwfx->nSamplesPerSec = PCM_Formats[afd->dwFormatIndex].rate;
771 afd->pwfx->wBitsPerSample = PCM_Formats[afd->dwFormatIndex].nBits;
772 /* native MSACM uses a PCMWAVEFORMAT structure, so cbSize is not accessible
773 * afd->pwfx->cbSize = 0;
775 afd->pwfx->nBlockAlign =
776 (afd->pwfx->nChannels * afd->pwfx->wBitsPerSample) / 8;
777 afd->pwfx->nAvgBytesPerSec =
778 afd->pwfx->nSamplesPerSec * afd->pwfx->nBlockAlign;
779 break;
780 case WAVE_FORMAT_MPEGLAYER3:
781 case WAVE_FORMAT_MPEG:
782 WARN("Encoding to MPEG is not supported\n");
783 return ACMERR_NOTPOSSIBLE;
784 default:
785 WARN("Unsupported tag %08x\n", afd->dwFormatTag);
786 return MMSYSERR_INVALPARAM;
788 break;
789 default:
790 WARN("Unsupported query %08x\n", dwQuery);
791 return MMSYSERR_NOTSUPPORTED;
793 afd->fdwSupport = ACMDRIVERDETAILS_SUPPORTF_CODEC;
794 afd->szFormat[0] = 0; /* let MSACM format this for us... */
796 return MMSYSERR_NOERROR;
799 /***********************************************************************
800 * MPEG3_FormatSuggest
803 static LRESULT MPEG3_FormatSuggest(PACMDRVFORMATSUGGEST adfs)
805 /* some tests ... */
806 if (adfs->cbwfxSrc < sizeof(PCMWAVEFORMAT) ||
807 adfs->cbwfxDst < sizeof(PCMWAVEFORMAT) ||
808 MPEG3_GetFormatIndex(adfs->pwfxSrc) == 0xFFFFFFFF) return ACMERR_NOTPOSSIBLE;
809 /* FIXME: should do those tests against the real size (according to format tag */
811 /* If no suggestion for destination, then copy source value */
812 if (!(adfs->fdwSuggest & ACM_FORMATSUGGESTF_NCHANNELS))
813 adfs->pwfxDst->nChannels = adfs->pwfxSrc->nChannels;
814 if (!(adfs->fdwSuggest & ACM_FORMATSUGGESTF_NSAMPLESPERSEC))
815 adfs->pwfxDst->nSamplesPerSec = adfs->pwfxSrc->nSamplesPerSec;
816 if (!(adfs->fdwSuggest & ACM_FORMATSUGGESTF_WBITSPERSAMPLE))
817 adfs->pwfxDst->wBitsPerSample = 16;
818 if (!(adfs->fdwSuggest & ACM_FORMATSUGGESTF_WFORMATTAG))
820 if (adfs->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM)
822 WARN("Encoding to MPEG is not supported\n");
823 return ACMERR_NOTPOSSIBLE;
825 else
826 adfs->pwfxDst->wFormatTag = WAVE_FORMAT_PCM;
829 /* check if result is ok */
830 if (MPEG3_GetFormatIndex(adfs->pwfxDst) == 0xFFFFFFFF) return ACMERR_NOTPOSSIBLE;
832 /* recompute other values */
833 switch (adfs->pwfxDst->wFormatTag)
835 case WAVE_FORMAT_PCM:
836 adfs->pwfxDst->nBlockAlign = (adfs->pwfxDst->nChannels * adfs->pwfxDst->wBitsPerSample) / 8;
837 adfs->pwfxDst->nAvgBytesPerSec = adfs->pwfxDst->nSamplesPerSec * adfs->pwfxDst->nBlockAlign;
838 break;
839 case WAVE_FORMAT_MPEG:
840 case WAVE_FORMAT_MPEGLAYER3:
841 WARN("Encoding to MPEG is not supported\n");
842 return ACMERR_NOTPOSSIBLE;
843 break;
844 default:
845 FIXME("\n");
846 break;
849 return MMSYSERR_NOERROR;
852 /***********************************************************************
853 * MPEG3_StreamSize
856 static LRESULT MPEG3_StreamSize(PACMDRVSTREAMINSTANCE adsi, PACMDRVSTREAMSIZE adss)
858 DWORD nblocks;
860 switch (adss->fdwSize)
862 case ACM_STREAMSIZEF_DESTINATION:
863 /* cbDstLength => cbSrcLength */
864 if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM &&
865 (adsi->pwfxDst->wFormatTag == WAVE_FORMAT_MPEGLAYER3 ||
866 adsi->pwfxDst->wFormatTag == WAVE_FORMAT_MPEG))
868 nblocks = (adss->cbDstLength - 3000) / (DWORD)(adsi->pwfxDst->nAvgBytesPerSec * 1152 / adsi->pwfxDst->nSamplesPerSec + 0.5);
869 if (nblocks == 0)
870 return ACMERR_NOTPOSSIBLE;
871 adss->cbSrcLength = nblocks * 1152 * adsi->pwfxSrc->nBlockAlign;
873 else if ((adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_MPEGLAYER3 ||
874 adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_MPEG) &&
875 adsi->pwfxDst->wFormatTag == WAVE_FORMAT_PCM)
877 nblocks = adss->cbDstLength / (adsi->pwfxDst->nBlockAlign * 1152);
878 if (nblocks == 0)
879 return ACMERR_NOTPOSSIBLE;
880 adss->cbSrcLength = nblocks * (DWORD)(adsi->pwfxSrc->nAvgBytesPerSec * 1152 / adsi->pwfxSrc->nSamplesPerSec);
882 else
884 return MMSYSERR_NOTSUPPORTED;
886 break;
887 case ACM_STREAMSIZEF_SOURCE:
888 /* cbSrcLength => cbDstLength */
889 if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM &&
890 (adsi->pwfxDst->wFormatTag == WAVE_FORMAT_MPEGLAYER3 ||
891 adsi->pwfxDst->wFormatTag == WAVE_FORMAT_MPEG))
893 nblocks = adss->cbSrcLength / (adsi->pwfxSrc->nBlockAlign * 1152);
894 if (adss->cbSrcLength % (DWORD)(adsi->pwfxSrc->nBlockAlign * 1152))
895 /* Round block count up. */
896 nblocks++;
897 if (nblocks == 0)
898 return ACMERR_NOTPOSSIBLE;
899 adss->cbDstLength = 3000 + nblocks * (DWORD)(adsi->pwfxDst->nAvgBytesPerSec * 1152 / adsi->pwfxDst->nSamplesPerSec + 0.5);
901 else if ((adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_MPEGLAYER3 ||
902 adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_MPEG) &&
903 adsi->pwfxDst->wFormatTag == WAVE_FORMAT_PCM)
905 nblocks = adss->cbSrcLength / (DWORD)(adsi->pwfxSrc->nAvgBytesPerSec * 1152 / adsi->pwfxSrc->nSamplesPerSec);
906 if (adss->cbSrcLength % (DWORD)(adsi->pwfxSrc->nAvgBytesPerSec * 1152 / adsi->pwfxSrc->nSamplesPerSec))
907 /* Round block count up. */
908 nblocks++;
909 if (nblocks == 0)
910 return ACMERR_NOTPOSSIBLE;
911 adss->cbDstLength = nblocks * 1152 * adsi->pwfxDst->nBlockAlign;
913 else
915 return MMSYSERR_NOTSUPPORTED;
917 break;
918 default:
919 WARN("Unsupported query %08x\n", adss->fdwSize);
920 return MMSYSERR_NOTSUPPORTED;
922 return MMSYSERR_NOERROR;
925 /***********************************************************************
926 * MPEG3_StreamConvert
929 static LRESULT MPEG3_StreamConvert(PACMDRVSTREAMINSTANCE adsi, PACMDRVSTREAMHEADER adsh)
931 AcmMpeg3Data* aad = (AcmMpeg3Data*)adsi->dwDriver;
932 DWORD nsrc = adsh->cbSrcLength;
933 DWORD ndst = adsh->cbDstLength;
935 if (adsh->fdwConvert &
936 ~(ACM_STREAMCONVERTF_BLOCKALIGN|
937 ACM_STREAMCONVERTF_END|
938 ACM_STREAMCONVERTF_START))
940 FIXME("Unsupported fdwConvert (%08x), ignoring it\n", adsh->fdwConvert);
942 /* ACM_STREAMCONVERTF_BLOCKALIGN
943 * currently all conversions are block aligned, so do nothing for this flag
944 * ACM_STREAMCONVERTF_END
945 * no pending data, so do nothing for this flag
947 if ((adsh->fdwConvert & ACM_STREAMCONVERTF_START))
949 MPEG3_Reset(adsi, aad);
952 aad->convert(adsi, adsh->pbSrc, &nsrc, adsh->pbDst, &ndst);
953 adsh->cbSrcLengthUsed = nsrc;
954 adsh->cbDstLengthUsed = ndst;
956 return MMSYSERR_NOERROR;
959 /**************************************************************************
960 * MPEG3_DriverProc [exported]
962 LRESULT CALLBACK MPEG3_DriverProc(DWORD_PTR dwDevID, HDRVR hDriv, UINT wMsg,
963 LPARAM dwParam1, LPARAM dwParam2)
965 TRACE("(%08lx %p %04x %08lx %08lx);\n",
966 dwDevID, hDriv, wMsg, dwParam1, dwParam2);
968 switch (wMsg)
970 case DRV_LOAD: return 1;
971 case DRV_FREE: return 1;
972 case DRV_OPEN: return MPEG3_drvOpen((LPSTR)dwParam1);
973 case DRV_CLOSE: return MPEG3_drvClose(dwDevID);
974 case DRV_ENABLE: return 1;
975 case DRV_DISABLE: return 1;
976 case DRV_QUERYCONFIGURE: return 1;
977 case DRV_CONFIGURE: MessageBoxA(0, "MPEG3 filter !", "Wine Driver", MB_OK); return 1;
978 case DRV_INSTALL: return DRVCNF_RESTART;
979 case DRV_REMOVE: return DRVCNF_RESTART;
981 case ACMDM_DRIVER_NOTIFY:
982 /* no caching from other ACM drivers is done so far */
983 return MMSYSERR_NOERROR;
985 case ACMDM_DRIVER_DETAILS:
986 return MPEG3_DriverDetails((PACMDRIVERDETAILSW)dwParam1);
988 case ACMDM_FORMATTAG_DETAILS:
989 return MPEG3_FormatTagDetails((PACMFORMATTAGDETAILSW)dwParam1, dwParam2);
991 case ACMDM_FORMAT_DETAILS:
992 return MPEG3_FormatDetails((PACMFORMATDETAILSW)dwParam1, dwParam2);
994 case ACMDM_FORMAT_SUGGEST:
995 return MPEG3_FormatSuggest((PACMDRVFORMATSUGGEST)dwParam1);
997 case ACMDM_STREAM_OPEN:
998 return MPEG3_StreamOpen((PACMDRVSTREAMINSTANCE)dwParam1);
1000 case ACMDM_STREAM_CLOSE:
1001 return MPEG3_StreamClose((PACMDRVSTREAMINSTANCE)dwParam1);
1003 case ACMDM_STREAM_SIZE:
1004 return MPEG3_StreamSize((PACMDRVSTREAMINSTANCE)dwParam1, (PACMDRVSTREAMSIZE)dwParam2);
1006 case ACMDM_STREAM_CONVERT:
1007 return MPEG3_StreamConvert((PACMDRVSTREAMINSTANCE)dwParam1, (PACMDRVSTREAMHEADER)dwParam2);
1009 case ACMDM_HARDWARE_WAVE_CAPS_INPUT:
1010 case ACMDM_HARDWARE_WAVE_CAPS_OUTPUT:
1011 /* this converter is not a hardware driver */
1012 case ACMDM_FILTERTAG_DETAILS:
1013 case ACMDM_FILTER_DETAILS:
1014 /* this converter is not a filter */
1015 case ACMDM_STREAM_RESET:
1016 /* only needed for asynchronous driver... we aren't, so just say it */
1017 return MMSYSERR_NOTSUPPORTED;
1018 case ACMDM_STREAM_PREPARE:
1019 case ACMDM_STREAM_UNPREPARE:
1020 /* nothing special to do here... so don't do anything */
1021 return MMSYSERR_NOERROR;
1023 default:
1024 return DefDriverProc(dwDevID, hDriv, wMsg, dwParam1, dwParam2);