Как конвертировать WMA в WAV(PCM) функциями acmStreamConvert
От: diduk  
Дата: 03.11.03 17:15
Оценка:
Помогите, пожалуйста, есть проблема при конвертации WMA в WAV(PCM).
Функция acmStreamConvert на некоторых блоках возвращает код ошибки.
Нет ли у кого работающего кода, очень надо...


#include <windows.h>
#include <stdio.h>
#include <assert.h>
#include <mmreg.h>
#include <msacm.h>

#define WMA_BLOCK_SIZE 1000

#define SOURCE_WMA "d:wma_simple.wma"
#define OUTPUT_PCM_FILE "d:wma_simple.wav"

HACMDRIVERID WMADriverID[16];
int nWMADriverID=0;

BOOL CALLBACK acmDriverEnumCallback( HACMDRIVERID hadid, DWORD dwInstance, DWORD fdwSupport )
{
  if( fdwSupport & ACMDRIVERDETAILS_SUPPORTF_CODEC )
  {
    MMRESULT mmr;

    ACMDRIVERDETAILS details;
    details.cbStruct = sizeof(ACMDRIVERDETAILS);
    mmr = acmDriverDetails( hadid, &details, 0 );

    HACMDRIVER driver;
    mmr = acmDriverOpen( &driver, hadid, 0 );

    for (int i = 0; i < (int)details.cFormatTags; i++ )
    {
      ACMFORMATTAGDETAILS fmtDetails;
      ZeroMemory( &fmtDetails, sizeof(fmtDetails) );
      fmtDetails.cbStruct = sizeof(ACMFORMATTAGDETAILS);
      fmtDetails.dwFormatTagIndex = i;
      mmr = acmFormatTagDetails( driver, &fmtDetails, ACM_FORMATTAGDETAILSF_INDEX );

      if (fmtDetails.dwFormatTag==0x160)
      {
              OutputDebugString( "Found an WMA-capable ACM codec: " );
              OutputDebugString( details.szLongName );
              OutputDebugString( "\n" );

        WMADriverID[nWMADriverID++]=hadid;
      }
    }

    mmr = acmDriverClose( driver, 0 );
  }

  return true;
}

HACMSTREAM g_wmastream = NULL;

void ChooseFormat(WAVEFORMATEX *wmaFormat, WAVEFORMATEX *wavFormat)
{
 ACMFORMATCHOOSE afc;
 int MaxSize;
 int i;

 memset(&afc,0,sizeof(afc));
 afc.cbStruct=sizeof(afc);
 MaxSize=sizeof(WAVEFORMATEX);
 acmMetrics(0,ACM_METRIC_MAX_SIZE_FORMAT, &MaxSize);

 afc.pwfx=wmaFormat;
 afc.cbwfx=MaxSize;

 afc.hwndOwner=NULL;
 afc.fdwEnum=ACM_FORMATENUMF_CONVERT;
 afc.pwfxEnum=wavFormat;

 afc.fdwEnum=ACM_FORMATENUMF_SUGGEST  |
             ACM_FORMATENUMF_NCHANNELS |
             ACM_FORMATENUMF_NSAMPLESPERSEC;

 afc.pszTitle="Select new format";
 acmFormatChoose(&afc);

 for(i=0;i < ((WAVEFORMATEX *)wmaFormat)->cbSize;i++)
 {
    printf("%02x ",*(wmaFormat+sizeof(WAVEFORMATEX)+i));
 }

 printf("\n");
}

convertWMA()
{
  MMRESULT mmr;
  
  acmDriverEnum( acmDriverEnumCallback, 0, 0 );

  if(nWMADriverID == 0)
  {
    OutputDebugString( "No WMA decoders found!\n" );
    return E_FAIL;
  }

  HACMDRIVER hWMADriver;
  int index=1;

  acmDriverOpen(&hWMADriver,WMADriverID[index],0);

  DWORD maxFormatSize = 0;
  mmr = acmMetrics( NULL, ACM_METRIC_MAX_SIZE_FORMAT, &maxFormatSize );

  LPWAVEFORMATEX wmaFormat   = (LPWAVEFORMATEX) LocalAlloc( LPTR, maxFormatSize );
  memset(wmaFormat,0,maxFormatSize);

  LPWAVEFORMATEX wavFormat   = (LPWAVEFORMATEX) LocalAlloc( LPTR, maxFormatSize );
  memset(wavFormat,0,maxFormatSize);
  wavFormat->wFormatTag      = WAVE_FORMAT_PCM;
  wavFormat->nChannels       = 2;
  wavFormat->nSamplesPerSec  = 44100;
  wavFormat->nAvgBytesPerSec = 4 * 44100;
  wavFormat->nBlockAlign     = 4;
  wavFormat->wBitsPerSample  = 16;
  wavFormat->cbSize          = 0;

  ChooseFormat(wmaFormat, wavFormat);

  g_wmastream = NULL;
  mmr = acmStreamOpen( &g_wmastream,
                                 hWMADriver,
                                 (LPWAVEFORMATEX) wmaFormat,
                                 wavFormat,
                                 NULL,
                                 0,
                                 0,
                                 0
                                 );
  
  LocalFree( wmaFormat );
  LocalFree( wavFormat );
  
  switch( mmr )
  {
    case MMSYSERR_NOERROR:
      break; // success!
    case MMSYSERR_INVALPARAM:
      assert( !"Invalid parameters passed to acmStreamOpen" );
      return E_FAIL;
    case ACMERR_NOTPOSSIBLE:
      assert( !"No ACM filter found capable of decoding WMA" );
      return E_FAIL;
    default:
      assert( !"Some error opening ACM decoding stream!" );
      return E_FAIL;
  }
  
  // WMA stream converter opened correctly
  // now, let's open a file, read in a bunch of WMA data, and convert it!
  
  // open file
  FILE *fpIn = fopen( SOURCE_WMA, "rb" );

  if( fpIn == NULL )
  {
    assert( !"can't open input WMA file!" );
    return E_FAIL;
  }
  
  // find out how big the decompressed buffer will be
  unsigned long rawbufsize = 0;
  mmr = acmStreamSize( g_wmastream, WMA_BLOCK_SIZE, &rawbufsize, ACM_STREAMSIZEF_SOURCE );
  assert( mmr == 0 );
  assert( rawbufsize > 0 );

  // allocate our I/O buffers
  LPBYTE wmabuf = (LPBYTE) LocalAlloc( LPTR, WMA_BLOCK_SIZE );
  LPBYTE rawbuf = (LPBYTE) LocalAlloc( LPTR, rawbufsize );
  
  // prepare the decoder
  ACMSTREAMHEADER wmastreamHead;
  ZeroMemory( &wmastreamHead, sizeof(ACMSTREAMHEADER ) );
  wmastreamHead.cbStruct = sizeof(ACMSTREAMHEADER );
  wmastreamHead.pbSrc = wmabuf;
  wmastreamHead.cbSrcLength = WMA_BLOCK_SIZE;
  wmastreamHead.pbDst = rawbuf;
  wmastreamHead.cbDstLength = rawbufsize;
  mmr = acmStreamPrepareHeader( g_wmastream, &wmastreamHead, 0 );
  assert( mmr == 0 );
  
  // let's dump this data off to disk (for debug checking!)
  FILE *fpOut = fopen( OUTPUT_PCM_FILE, "wb" );

  if( fpOut == NULL )
  {
    assert( !"can't open output PCM file!" );
    return E_FAIL;
  }
  
  while(1)
  {
    // suck in some WMA data
    int count = fread( wmabuf, 1, WMA_BLOCK_SIZE, fpIn );
    if( count != WMA_BLOCK_SIZE )
      break;
  
    // convert the data
    mmr = acmStreamConvert( g_wmastream, &wmastreamHead, ACM_STREAMCONVERTF_BLOCKALIGN );

    switch( mmr )
    {
      case 0:
        break; // success!
      case ACMERR_BUSY:
        printf( "acmStreamConvert FAILED\n" );
        return E_FAIL;
      case ACMERR_UNPREPARED:
        printf( "acmStreamConvert FAILED\n" );
        return E_FAIL;
      case MMSYSERR_INVALFLAG:
        printf( "acmStreamConvert FAILED\n" );
        return E_FAIL;
      case MMSYSERR_INVALHANDLE:
        printf( "acmStreamConvert FAILED\n" );
        return E_FAIL;
      case MMSYSERR_INVALPARAM:
        printf( "acmStreamConvert FAILED\n" );
        return E_FAIL;
      default:
        assert( !"Some error opening ACM decoding stream!" );
        return E_FAIL;
        break;
    }
  
    // write the decoded PCM to disk
    count = fwrite( rawbuf, 1, wmastreamHead.cbDstLengthUsed, fpOut );
    assert( count == (int)wmastreamHead.cbDstLengthUsed );
  };
  
  // clean up after yourself like a good little boy
  fclose( fpIn );
  fclose( fpOut );

  mmr = acmStreamUnprepareHeader( g_wmastream, &wmastreamHead, 0 );
  assert( mmr == 0 );

  LocalFree(rawbuf);
  LocalFree(wmabuf);

  mmr = acmStreamClose( g_wmastream, 0 );
  assert( mmr == 0 );
  
  return S_OK;
}

void main()
{
 convertWMA();
}
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.