pcm to a-law
От: pigeon Великобритания
Дата: 18.11.04 14:31
Оценка:
Привет всем!!!
Может кто сталкивался с подобной проблемой: необходимо переконвертить pcm (Моно 8 бит 8кГ) в такой же pcm но с a-law кодировкой.Нашел здесь пример который делал что-то подобное, подкрутил его под свои нужды,но при вызове диалога выбора
 acmFormatChoose(...)
с параметрами моего файла (Моно 8 бит 8кГ) режим кодировки Программа сжатия Microsoft CCITT G.711 A-Law / u-Law который мне нужен недоступен.

Многострадальный код — ниже
#include <windows.h>
#include <stdio.h>
#include <assert.h>
#include <mmreg.h>
#include <msacm.h>

#define WMA_BLOCK_SIZE 1000

#define SOURCE_WMA "D:\\Speech\\formula_1.pcm"
#define OUTPUT_PCM_FILE "d:\\Speech\\wma_simple.pcm"

HACMDRIVERID g_CCITT; 


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 ( !strcmp( fmtDetails.szFormatTag , "CCITT A-Law" ) )
      {
        printf( "%s\nTag = %i  TagIndex = %i\n" ,details.szLongName, fmtDetails.dwFormatTag , fmtDetails.dwFormatTagIndex );    
        g_CCITT = hadid;
      }
    }

    mmr = acmDriverClose( driver, 0 );
    return true;
  }

  return false;
}

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.fdwStyle = ACMFORMATCHOOSE_STYLEF_INITTOWFXSTRUCT;
 afc.pwfx=wmaFormat;
 afc.cbwfx=MaxSize;

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

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

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

  HACMDRIVER hWMADriver;
  int index=0;

  mmr = acmDriverOpen(&hWMADriver,g_CCITT,0);

  if ( mmr!=0 )
  {
    printf("Error open device %i",mmr );    
    return E_FAIL;
  }        

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



  WAVEFORMATEX wavFormat;
  memset(&wavFormat,0,maxFormatSize);

  int BytesPerSample = (8 + 7) / 8;
  wavFormat.wFormatTag      = WAVE_FORMAT_PCM;
  wavFormat.nChannels       = 1;
  wavFormat.nBlockAlign     = 1 * BytesPerSample;
  wavFormat.nSamplesPerSec  = 8000;
  wavFormat.nAvgBytesPerSec = wavFormat.nSamplesPerSec * wavFormat.nBlockAlign;
  wavFormat.wBitsPerSample  = 8;
  wavFormat.cbSize          = 0;


  WAVEFORMATEX wmaFormat;
  memset(&wmaFormat,0,maxFormatSize);

  ChooseFormat(&wmaFormat, &wavFormat);

  g_wmastream = NULL;

  mmr = acmStreamOpen( &g_wmastream,
                                 hWMADriver,
                                 &wmaFormat,
                                 &wavFormat,
                                 NULL,
                                 0,
                                 0,
                                 0
                                 );
  
 
  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;
  }

 
 
  // 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
  mmr = acmStreamOpen( &g_wmastream,
                                 hWMADriver,
                                 &wmaFormat,
                                 &wavFormat,
                                 NULL,
                                 0,
                                 0,
                                 ACM_STREAMOPENF_NONREALTIME 
                                 );
  unsigned long rawbufsize = 0;
  mmr = acmStreamSize( g_wmastream, WMA_BLOCK_SIZE, &rawbufsize, ACM_STREAMSIZEF_SOURCE );
  assert( mmr == 0 );
  assert( rawbufsize > 0 );

 
  LPBYTE wmabuf = (LPBYTE) malloc(  WMA_BLOCK_SIZE );
  LPBYTE rawbuf = (LPBYTE) malloc(  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 );

  free(rawbuf);
  free(wmabuf);
  mmr = acmStreamClose( g_wmastream, 0 );

  assert( mmr == 0 );
  
  return S_OK;
}

void main()
{
 convertWMA();
}
"Если вы держите слона за заднюю ногу, а он вырывается, то самое лучшее отпустить его" — Авраам Линкольн
Premature optimization is the root of all evil in programming. Donald Knuth
Re: pcm to a-law
От: Odi$$ey Россия http://malgarr.blogspot.com/
Дата: 18.11.04 16:07
Оценка: 2 (1)
Здравствуйте, pigeon, Вы писали:

P>Может кто сталкивался с подобной проблемой: необходимо переконвертить pcm (Моно 8 бит 8кГ) в такой же pcm но с a-law кодировкой.Нашел здесь пример который делал что-то подобное, подкрутил его под свои нужды,но при вызове диалога выбора

P>
 acmFormatChoose(...)
с параметрами моего файла (Моно 8 бит 8кГ) режим кодировки Программа сжатия Microsoft CCITT G.711 A-Law / u-Law который мне нужен недоступен.


да, чтобы получить A-Law 8 кГц 8 бит моно PCM должен быть 8кГц 16 бит mono, по другому acmStreamConvert не умеет. Варианты переконвертации при помощи acmStreamConvert вообще очень ограничены для любого формата.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.