[WINEMP3.ACM] Sync with Wine Staging 4.18. CORE-16441
[reactos.git] / dll / win32 / winemp3.acm / mpegl3.c
index 1e09c10..2e92937 100644 (file)
@@ -29,7 +29,7 @@
 #include <string.h>
 
 #ifdef HAVE_MPG123_H
-# include "mpg123.h"
+# include <mpg123.h>
 #else
 # ifdef HAVE_COREAUDIO_COREAUDIO_H
 #  include <CoreFoundation/CoreFoundation.h>
@@ -89,9 +89,6 @@ static const Format MPEG3_Formats[] =
     {1,  0, 48000}, {2,  0, 48000}
 };
 
-#define        NUM_PCM_FORMATS         (sizeof(PCM_Formats) / sizeof(PCM_Formats[0]))
-#define        NUM_MPEG3_FORMATS       (sizeof(MPEG3_Formats) / sizeof(MPEG3_Formats[0]))
-
 /***********************************************************************
  *           MPEG3_GetFormatIndex
  */
@@ -103,11 +100,12 @@ static    DWORD   MPEG3_GetFormatIndex(LPWAVEFORMATEX wfx)
     switch (wfx->wFormatTag)
     {
     case WAVE_FORMAT_PCM:
-       hi = NUM_PCM_FORMATS;
+       hi = ARRAY_SIZE(PCM_Formats);
        fmts = PCM_Formats;
        break;
+    case WAVE_FORMAT_MPEG:
     case WAVE_FORMAT_MPEGLAYER3:
-       hi = NUM_MPEG3_FORMATS;
+       hi = ARRAY_SIZE(MPEG3_Formats);
        fmts = MPEG3_Formats;
        break;
     default:
@@ -192,7 +190,7 @@ static void mp3_horse(PACMDRVSTREAMINSTANCE adsi,
             TRACE("New format: %li Hz, %i channels, encoding value %i\n", rate, channels, enc);
         }
         dpos += size;
-        if (dpos > *ndst) break;
+        if (dpos >= *ndst) break;
     } while (ret != MPG123_ERR && ret != MPG123_NEED_MORE);
     *ndst = dpos;
 }
@@ -214,6 +212,7 @@ static void MPEG3_Reset(PACMDRVSTREAMINSTANCE adsi, AcmMpeg3Data* aad)
  */
 static LRESULT MPEG3_StreamOpen(PACMDRVSTREAMINSTANCE adsi)
 {
+    LRESULT error = MMSYSERR_NOTSUPPORTED;
     AcmMpeg3Data*      aad;
     int err;
 
@@ -233,9 +232,22 @@ static     LRESULT MPEG3_StreamOpen(PACMDRVSTREAMINSTANCE adsi)
     {
        goto theEnd;
     }
-    else if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_MPEGLAYER3 &&
+    else if ((adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_MPEGLAYER3 ||
+              adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_MPEG) &&
              adsi->pwfxDst->wFormatTag == WAVE_FORMAT_PCM)
     {
+        if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_MPEGLAYER3)
+        {
+            MPEGLAYER3WAVEFORMAT *formatmp3 = (MPEGLAYER3WAVEFORMAT *)adsi->pwfxSrc;
+
+            if (adsi->pwfxSrc->cbSize < MPEGLAYER3_WFX_EXTRA_BYTES ||
+                formatmp3->wID != MPEGLAYER3_ID_MPEG)
+            {
+                error = ACMERR_NOTPOSSIBLE;
+                goto theEnd;
+            }
+        }
+
        /* resampling or mono <=> stereo not available
          * MPEG3 algo only define 16 bit per sample output
          */
@@ -246,11 +258,23 @@ static    LRESULT MPEG3_StreamOpen(PACMDRVSTREAMINSTANCE adsi)
         aad->convert = mp3_horse;
         aad->mh = mpg123_new(NULL,&err);
         mpg123_open_feed(aad->mh);
+
+#if MPG123_API_VERSION >= 31 /* needed for MPG123_IGNORE_FRAMEINFO enum value */
+        /* mpg123 may find a XING header in the mp3 and use that information
+         * to ask for seeks in order to read specific frames in the file.
+         * We cannot allow that since the caller application is feeding us.
+         * This fixes problems for mp3 files encoded with LAME (bug 42361)
+         */
+        mpg123_param(aad->mh, MPG123_ADD_FLAGS, MPG123_IGNORE_INFOFRAME, 0);
+#endif
     }
-    /* no encoding yet
     else if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM &&
-             adsi->pwfxDst->wFormatTag == WAVE_FORMAT_MPEGLAYER3)
-    */
+             (adsi->pwfxDst->wFormatTag == WAVE_FORMAT_MPEGLAYER3 ||
+              adsi->pwfxDst->wFormatTag == WAVE_FORMAT_MPEG))
+    {
+        WARN("Encoding to MPEG is not supported\n");
+        goto theEnd;
+    }
     else goto theEnd;
     MPEG3_Reset(adsi, aad);
 
@@ -259,7 +283,7 @@ static      LRESULT MPEG3_StreamOpen(PACMDRVSTREAMINSTANCE adsi)
  theEnd:
     HeapFree(GetProcessHeap(), 0, aad);
     adsi->dwDriver = 0L;
-    return MMSYSERR_NOTSUPPORTED;
+    return error;
 }
 
 /***********************************************************************
@@ -290,7 +314,7 @@ static const unsigned short Mp3SampleRates[2][4] =
 
 typedef struct tagAcmMpeg3Data
 {
-    LRESULT (*convert)(PACMDRVSTREAMINSTANCE adsi, const unsigned char*,
+    LRESULT (*convert)(PACMDRVSTREAMINSTANCE adsi, unsigned char*,
                        LPDWORD, unsigned char*, LPDWORD);
     AudioConverterRef acr;
     AudioStreamBasicDescription in,out;
@@ -395,7 +419,7 @@ static SInt32 Mp3GetPacketLength(const unsigned char* src)
  and *nsrc to the length of the unwanted data and return no error.
  */
 static LRESULT mp3_leopard_horse(PACMDRVSTREAMINSTANCE adsi,
-                                 const unsigned char* src, LPDWORD nsrc,
+                                 unsigned char* src, LPDWORD nsrc,
                                  unsigned char* dst, LPDWORD ndst)
 {
     OSStatus err;
@@ -406,7 +430,7 @@ static LRESULT mp3_leopard_horse(PACMDRVSTREAMINSTANCE adsi,
 
     TRACE("ndst %u %p  <-  %u %p\n", *ndst, dst, *nsrc, src);
 
-    TRACE("First 16 bytes to input: %s\n", wine_dbgstr_an(src, 16));
+    TRACE("First 16 bytes to input: %s\n", wine_dbgstr_an((const char *)src, 16));
 
     /* Parse ID3 tag */
     if (!memcmp(src, "ID3", 3) && amd->tagBytesLeft == -1)
@@ -429,7 +453,7 @@ static LRESULT mp3_leopard_horse(PACMDRVSTREAMINSTANCE adsi,
     {
         src += amd->tagBytesLeft;
         *nsrc -= amd->tagBytesLeft;
-        TRACE("Skipping %d for ID3 tag\n", amd->tagBytesLeft);
+        TRACE("Skipping %ld for ID3 tag\n", amd->tagBytesLeft);
     }
 
     /*
@@ -460,7 +484,7 @@ static LRESULT mp3_leopard_horse(PACMDRVSTREAMINSTANCE adsi,
                 syncSkip = psrc - src;
                 src += syncSkip;
                 *nsrc -= syncSkip;
-                TRACE("Skipping %d for frame sync\n", syncSkip);
+                TRACE("Skipping %ld for frame sync\n", syncSkip);
             }
             break;
         }
@@ -583,7 +607,8 @@ static LRESULT MPEG3_StreamOpen(PACMDRVSTREAMINSTANCE adsi)
 
     adsi->dwDriver = (DWORD_PTR)aad;
 
-    if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_MPEGLAYER3 &&
+    if ((adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_MPEGLAYER3 ||
+         adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_MPEG) &&
         adsi->pwfxDst->wFormatTag == WAVE_FORMAT_PCM)
     {
         OSStatus err;
@@ -655,22 +680,22 @@ static    LRESULT MPEG3_DriverDetails(PACMDRIVERDETAILSW add)
 {
     add->fccType = ACMDRIVERDETAILS_FCCTYPE_AUDIOCODEC;
     add->fccComp = ACMDRIVERDETAILS_FCCCOMP_UNDEFINED;
-    add->wMid = 0xFF;
-    add->wPid = 0x00;
+    add->wMid = MM_FRAUNHOFER_IIS;
+    add->wPid = MM_FHGIIS_MPEGLAYER3_DECODE;
     add->vdwACM = 0x01000000;
     add->vdwDriver = 0x01000000;
     add->fdwSupport = ACMDRIVERDETAILS_SUPPORTF_CODEC;
-    add->cFormatTags = 2; /* PCM, MPEG3 */
+    add->cFormatTags = 3; /* PCM, MPEG3 */
     add->cFilterTags = 0;
     add->hicon = NULL;
-    MultiByteToWideChar( CP_ACP, 0, "WINE-MPEG3", -1,
-                         add->szShortName, sizeof(add->szShortName)/sizeof(WCHAR) );
+    MultiByteToWideChar( CP_ACP, 0, "MPEG Layer-3 Codec", -1,
+                         add->szShortName, ARRAY_SIZE( add->szShortName ));
     MultiByteToWideChar( CP_ACP, 0, "Wine MPEG3 decoder", -1,
-                         add->szLongName, sizeof(add->szLongName)/sizeof(WCHAR) );
+                         add->szLongName, ARRAY_SIZE( add->szLongName ));
     MultiByteToWideChar( CP_ACP, 0, "Brought to you by the Wine team...", -1,
-                         add->szCopyright, sizeof(add->szCopyright)/sizeof(WCHAR) );
+                         add->szCopyright, ARRAY_SIZE( add->szCopyright ));
     MultiByteToWideChar( CP_ACP, 0, "Refer to LICENSE file", -1,
-                         add->szLicensing, sizeof(add->szLicensing)/sizeof(WCHAR) );
+                         add->szLicensing, ARRAY_SIZE( add->szLicensing ));
     add->szFeatures[0] = 0;
 
     return MMSYSERR_NOERROR;
@@ -684,24 +709,26 @@ static    LRESULT MPEG3_FormatTagDetails(PACMFORMATTAGDETAILSW aftd, DWORD dwQuery)
 {
     static const WCHAR szPcm[]={'P','C','M',0};
     static const WCHAR szMpeg3[]={'M','P','e','g','3',0};
+    static const WCHAR szMpeg[]={'M','P','e','g',0};
 
     switch (dwQuery)
     {
     case ACM_FORMATTAGDETAILSF_INDEX:
-       if (aftd->dwFormatTagIndex >= 2) return ACMERR_NOTPOSSIBLE;
+       if (aftd->dwFormatTagIndex > 2) return ACMERR_NOTPOSSIBLE;
        break;
     case ACM_FORMATTAGDETAILSF_LARGESTSIZE:
        if (aftd->dwFormatTag == WAVE_FORMAT_UNKNOWN)
         {
-            aftd->dwFormatTagIndex = 1; /* WAVE_FORMAT_MPEGLAYER3 is bigger than PCM */
+            aftd->dwFormatTagIndex = 2; /* WAVE_FORMAT_MPEG is biggest */
            break;
        }
-       /* fall thru */
+       /* fall through */
     case ACM_FORMATTAGDETAILSF_FORMATTAG:
        switch (aftd->dwFormatTag)
         {
        case WAVE_FORMAT_PCM:           aftd->dwFormatTagIndex = 0; break;
        case WAVE_FORMAT_MPEGLAYER3:    aftd->dwFormatTagIndex = 1; break;
+       case WAVE_FORMAT_MPEG:          aftd->dwFormatTagIndex = 2; break;
        default:                        return ACMERR_NOTPOSSIBLE;
        }
        break;
@@ -716,36 +743,25 @@ static    LRESULT MPEG3_FormatTagDetails(PACMFORMATTAGDETAILSW aftd, DWORD dwQuery)
     case 0:
        aftd->dwFormatTag = WAVE_FORMAT_PCM;
        aftd->cbFormatSize = sizeof(PCMWAVEFORMAT);
-       aftd->cStandardFormats = NUM_PCM_FORMATS;
+       aftd->cStandardFormats = ARRAY_SIZE(PCM_Formats);
         lstrcpyW(aftd->szFormatTag, szPcm);
         break;
     case 1:
        aftd->dwFormatTag = WAVE_FORMAT_MPEGLAYER3;
        aftd->cbFormatSize = sizeof(MPEGLAYER3WAVEFORMAT);
-       aftd->cStandardFormats = NUM_MPEG3_FORMATS;
+        aftd->cStandardFormats = 0;
         lstrcpyW(aftd->szFormatTag, szMpeg3);
        break;
+    case 2:
+       aftd->dwFormatTag = WAVE_FORMAT_MPEG;
+       aftd->cbFormatSize = sizeof(MPEG1WAVEFORMAT);
+        aftd->cStandardFormats = 0;
+        lstrcpyW(aftd->szFormatTag, szMpeg);
+       break;
     }
     return MMSYSERR_NOERROR;
 }
 
-static void fill_in_wfx(unsigned cbwfx, WAVEFORMATEX* wfx, unsigned bit_rate)
-{
-    MPEGLAYER3WAVEFORMAT*   mp3wfx = (MPEGLAYER3WAVEFORMAT*)wfx;
-
-    wfx->nAvgBytesPerSec = bit_rate / 8;
-    if (cbwfx >= sizeof(WAVEFORMATEX))
-        wfx->cbSize = sizeof(MPEGLAYER3WAVEFORMAT) - sizeof(WAVEFORMATEX);
-    if (cbwfx >= sizeof(MPEGLAYER3WAVEFORMAT))
-    {
-        mp3wfx->wID = MPEGLAYER3_ID_MPEG;
-        mp3wfx->fdwFlags = MPEGLAYER3_FLAG_PADDING_OFF;
-        mp3wfx->nBlockSize = (bit_rate * 144) / wfx->nSamplesPerSec;
-        mp3wfx->nFramesPerBlock = 1;
-        mp3wfx->nCodecDelay = 0x0571;
-    }
-}
-
 /***********************************************************************
  *           MPEG3_FormatDetails
  *
@@ -762,7 +778,7 @@ static      LRESULT MPEG3_FormatDetails(PACMFORMATDETAILSW afd, DWORD dwQuery)
        switch (afd->dwFormatTag)
         {
        case WAVE_FORMAT_PCM:
-           if (afd->dwFormatIndex >= NUM_PCM_FORMATS) return ACMERR_NOTPOSSIBLE;
+           if (afd->dwFormatIndex >= ARRAY_SIZE(PCM_Formats)) return ACMERR_NOTPOSSIBLE;
            afd->pwfx->nChannels = PCM_Formats[afd->dwFormatIndex].nChannels;
            afd->pwfx->nSamplesPerSec = PCM_Formats[afd->dwFormatIndex].rate;
            afd->pwfx->wBitsPerSample = PCM_Formats[afd->dwFormatIndex].nBits;
@@ -775,13 +791,9 @@ static     LRESULT MPEG3_FormatDetails(PACMFORMATDETAILSW afd, DWORD dwQuery)
                afd->pwfx->nSamplesPerSec * afd->pwfx->nBlockAlign;
            break;
        case WAVE_FORMAT_MPEGLAYER3:
-           if (afd->dwFormatIndex >= NUM_MPEG3_FORMATS) return ACMERR_NOTPOSSIBLE;
-           afd->pwfx->nChannels = MPEG3_Formats[afd->dwFormatIndex].nChannels;
-           afd->pwfx->nSamplesPerSec = MPEG3_Formats[afd->dwFormatIndex].rate;
-           afd->pwfx->wBitsPerSample = MPEG3_Formats[afd->dwFormatIndex].nBits;
-           afd->pwfx->nBlockAlign = 1;
-            fill_in_wfx(afd->cbwfx, afd->pwfx, 192000);
-           break;
+       case WAVE_FORMAT_MPEG:
+            WARN("Encoding to MPEG is not supported\n");
+            return ACMERR_NOTPOSSIBLE;
        default:
             WARN("Unsupported tag %08x\n", afd->dwFormatTag);
            return MMSYSERR_INVALPARAM;
@@ -814,18 +826,15 @@ static    LRESULT MPEG3_FormatSuggest(PACMDRVFORMATSUGGEST adfs)
        adfs->pwfxDst->nChannels = adfs->pwfxSrc->nChannels;
     if (!(adfs->fdwSuggest & ACM_FORMATSUGGESTF_NSAMPLESPERSEC))
         adfs->pwfxDst->nSamplesPerSec = adfs->pwfxSrc->nSamplesPerSec;
-
     if (!(adfs->fdwSuggest & ACM_FORMATSUGGESTF_WBITSPERSAMPLE))
-    {
-       if (adfs->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM)
-            adfs->pwfxDst->wBitsPerSample = 4;
-        else
-            adfs->pwfxDst->wBitsPerSample = 16;
-    }
+        adfs->pwfxDst->wBitsPerSample = 16;
     if (!(adfs->fdwSuggest & ACM_FORMATSUGGESTF_WFORMATTAG))
     {
        if (adfs->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM)
-            adfs->pwfxDst->wFormatTag = WAVE_FORMAT_MPEGLAYER3;
+        {
+            WARN("Encoding to MPEG is not supported\n");
+            return ACMERR_NOTPOSSIBLE;
+        }
         else
             adfs->pwfxDst->wFormatTag = WAVE_FORMAT_PCM;
     }
@@ -840,9 +849,10 @@ static     LRESULT MPEG3_FormatSuggest(PACMDRVFORMATSUGGEST adfs)
         adfs->pwfxDst->nBlockAlign = (adfs->pwfxDst->nChannels * adfs->pwfxDst->wBitsPerSample) / 8;
         adfs->pwfxDst->nAvgBytesPerSec = adfs->pwfxDst->nSamplesPerSec * adfs->pwfxDst->nBlockAlign;
         break;
+    case WAVE_FORMAT_MPEG:
     case WAVE_FORMAT_MPEGLAYER3:
-        adfs->pwfxDst->nBlockAlign = 1;
-        fill_in_wfx(adfs->cbwfxDst, adfs->pwfxDst, 192000);
+        WARN("Encoding to MPEG is not supported\n");
+        return ACMERR_NOTPOSSIBLE;
         break;
     default:
         FIXME("\n");
@@ -865,14 +875,16 @@ static    LRESULT MPEG3_StreamSize(PACMDRVSTREAMINSTANCE adsi, PACMDRVSTREAMSIZE ad
     case ACM_STREAMSIZEF_DESTINATION:
        /* cbDstLength => cbSrcLength */
        if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM &&
-           adsi->pwfxDst->wFormatTag == WAVE_FORMAT_MPEGLAYER3)
+            (adsi->pwfxDst->wFormatTag == WAVE_FORMAT_MPEGLAYER3 ||
+             adsi->pwfxDst->wFormatTag == WAVE_FORMAT_MPEG))
         {
             nblocks = (adss->cbDstLength - 3000) / (DWORD)(adsi->pwfxDst->nAvgBytesPerSec * 1152 / adsi->pwfxDst->nSamplesPerSec + 0.5);
             if (nblocks == 0)
                 return ACMERR_NOTPOSSIBLE;
             adss->cbSrcLength = nblocks * 1152 * adsi->pwfxSrc->nBlockAlign;
        }
-        else if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_MPEGLAYER3 &&
+        else if ((adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_MPEGLAYER3 ||
+                 adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_MPEG) &&
                  adsi->pwfxDst->wFormatTag == WAVE_FORMAT_PCM)
         {
             nblocks = adss->cbDstLength / (adsi->pwfxDst->nBlockAlign * 1152);
@@ -888,25 +900,27 @@ static    LRESULT MPEG3_StreamSize(PACMDRVSTREAMINSTANCE adsi, PACMDRVSTREAMSIZE ad
     case ACM_STREAMSIZEF_SOURCE:
        /* cbSrcLength => cbDstLength */
        if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM &&
-           adsi->pwfxDst->wFormatTag == WAVE_FORMAT_MPEGLAYER3)
+            (adsi->pwfxDst->wFormatTag == WAVE_FORMAT_MPEGLAYER3 ||
+             adsi->pwfxDst->wFormatTag == WAVE_FORMAT_MPEG))
         {
             nblocks = adss->cbSrcLength / (adsi->pwfxSrc->nBlockAlign * 1152);
-            if (nblocks == 0)
-                return ACMERR_NOTPOSSIBLE;
             if (adss->cbSrcLength % (DWORD)(adsi->pwfxSrc->nBlockAlign * 1152))
                 /* Round block count up. */
                 nblocks++;
+            if (nblocks == 0)
+                return ACMERR_NOTPOSSIBLE;
             adss->cbDstLength = 3000 + nblocks * (DWORD)(adsi->pwfxDst->nAvgBytesPerSec * 1152 / adsi->pwfxDst->nSamplesPerSec + 0.5);
        }
-        else if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_MPEGLAYER3 &&
+        else if ((adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_MPEGLAYER3 ||
+                 adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_MPEG) &&
                  adsi->pwfxDst->wFormatTag == WAVE_FORMAT_PCM)
         {
             nblocks = adss->cbSrcLength / (DWORD)(adsi->pwfxSrc->nAvgBytesPerSec * 1152 / adsi->pwfxSrc->nSamplesPerSec);
-            if (nblocks == 0)
-                return ACMERR_NOTPOSSIBLE;
             if (adss->cbSrcLength % (DWORD)(adsi->pwfxSrc->nAvgBytesPerSec * 1152 / adsi->pwfxSrc->nSamplesPerSec))
                 /* Round block count up. */
                 nblocks++;
+            if (nblocks == 0)
+                return ACMERR_NOTPOSSIBLE;
             adss->cbDstLength = nblocks * 1152 * adsi->pwfxDst->nBlockAlign;
        }
         else