Привет всем!!!
Может кто сталкивался с подобной проблемой: необходимо переконвертить 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();
}
"Если вы держите слона за заднюю ногу, а он вырывается, то самое лучшее отпустить его" — Авраам Линкольн
Здравствуйте, 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 вообще очень ограничены для любого формата.