www.gusucode.com > 用于语音视频聊天的类源码程序 > 用于语音视频聊天的类源码程序/TACMConvert.cpp
//--------------------------------------------------------------------------- #pragma hdrstop #include "TACMConvert.h" #include <vcl.h> extern TStrings *DebugMsg; BOOL CALLBACK find_driver_enum(HACMDRIVERID hadid, DWORD dwInstance, DWORD fdwSupport); BOOL CALLBACK find_format_enum(HACMDRIVERID hadid, LPACMFORMATDETAILS pafd, DWORD dwInstance, DWORD fdwSupport); //--------------------------------------------------------------------------- #pragma package(smart_init) // callback function for format enumeration TACMConvert::TACMConvert() { pwfDrv=NULL; ACMDrv=NULL; //初始化源数据格式 memset(&wfSrc, 0, sizeof(WAVEFORMATEX)); wfSrc.cbSize = 0; wfSrc.wFormatTag = WAVE_FORMAT_PCM; // pcm wfSrc.nChannels = 1; // mono wfSrc.nSamplesPerSec = SamplesPerSec; // 11.025 kHz wfSrc.wBitsPerSample = BitsPerSample; // 8 bit wfSrc.nBlockAlign = wfSrc.nChannels * wfSrc.wBitsPerSample / 8; wfSrc.nAvgBytesPerSec = wfSrc.nSamplesPerSec * wfSrc.nBlockAlign; } bool TACMConvert::Init() { //获取 ACMDrvID FIND_DRIVER_INFO fdi; fdi.ACMConvert=this; fdi.hadid = NULL; fdi.wFormatTag = WAVE_FORMAT_DSPGROUP_TRUESPEECH; MMRESULT mmr = acmDriverEnum(find_driver_enum, (DWORD)(VOID*)&fdi, 0); if(mmr==0 && fdi.hadid!=NULL) ACMDrvID = fdi.hadid; else return(false); // throw Exception("找不到音频压缩模块"); //打开ACMDrv mmr = acmDriverOpen(&ACMDrv, ACMDrvID, 0); if(mmr) return(false); // throw Exception("打开音频压缩模块失败"); //获取最大的 MAX_SIZE_FORMAT mmr = acmMetrics((HACMOBJ)ACMDrv, ACM_METRIC_MAX_SIZE_FORMAT, &MaxFromatSize); if(MaxFromatSize < sizeof(WAVEFORMATEX)) MaxFromatSize = sizeof(WAVEFORMATEX); // for MS-PCM pwfPCM=&wfSrc; /* pwfPCM=(WAVEFORMATEX*)malloc(MaxFromatSize); if(!GetDriverFormat(WAVE_FORMAT_PCM,pwfPCM)) { throw Exception("获取PCM格式失败"); return ; } DebugMsg->Add("PCM格式: "); DebugMsg->Add(" wFormatTag:"+IntToStr(pwfPCM->wFormatTag)); DebugMsg->Add(" nChannels:"+IntToStr(pwfPCM->nChannels)); DebugMsg->Add(" nSamplesPerSec:"+IntToStr(pwfPCM->nSamplesPerSec)); DebugMsg->Add(" nAvgBytesPerSec:"+IntToStr(pwfPCM->nAvgBytesPerSec)); DebugMsg->Add(" nBlockAlign:"+IntToStr(pwfPCM->nBlockAlign)); DebugMsg->Add(" wBitsPerSample:"+IntToStr(pwfPCM->wBitsPerSample)); DebugMsg->Add(" cbSize:"+IntToStr(pwfPCM->cbSize)); DebugMsg->Add(""); */ pwfDrv=(WAVEFORMATEX*)malloc(MaxFromatSize); if(!GetDriverFormat(WAVE_FORMAT_DSPGROUP_TRUESPEECH,pwfDrv)) return(false); // throw Exception("获取压缩格式失败"); /* DebugMsg->Add("压缩格式: "); DebugMsg->Add(" wFormatTag:"+IntToStr(pwfDrv->wFormatTag)); DebugMsg->Add(" nChannels:"+IntToStr(pwfDrv->nChannels)); DebugMsg->Add(" nSamplesPerSec:"+IntToStr(pwfDrv->nSamplesPerSec)); DebugMsg->Add(" nAvgBytesPerSec:"+IntToStr(pwfDrv->nAvgBytesPerSec)); DebugMsg->Add(" nBlockAlign:"+IntToStr(pwfDrv->nBlockAlign)); DebugMsg->Add(" wBitsPerSample:"+IntToStr(pwfDrv->wBitsPerSample)); DebugMsg->Add(" cbSize:"+IntToStr(pwfDrv->cbSize)); DebugMsg->Add(""); */ // mmr = acmStreamOpen(&sPCM_TRUESPEECH, ACMDrv, // driver handle pwfPCM, // source format pwfDrv, // destination format NULL, // no filter NULL, // no callback 0, // instance data (not used) ACM_STREAMOPENF_NONREALTIME); // flags if (mmr) return(false); // throw Exception("acmStreamOpen 失败 PCM->Drv :"+IntToStr(mmr)); mmr = acmStreamOpen(&sTRUESPEECH_PCM, ACMDrv, // driver handle pwfDrv, // source format pwfPCM, // destination format NULL, // no filter NULL, // no callback 0, // instance data (not used) ACM_STREAMOPENF_NONREALTIME); // flags if (mmr) return(false); // throw Exception("acmStreamOpen 失败 Drv->PCM :"+IntToStr(mmr)); return(true); } TACMConvert::~TACMConvert() { // free(pwfPCM); if(pwfDrv) free(pwfDrv); acmStreamClose(sPCM_TRUESPEECH, 0); acmStreamClose(sTRUESPEECH_PCM, 0); if(ACMDrv) acmDriverClose(ACMDrv, 0); } bool TACMConvert::Compress(BYTE *Data,int &DataLen) { //Src->PCM /* HACMSTREAM hstr = NULL; MMRESULT mmr = acmStreamOpen(&hstr, NULL, // any driver &wfSrc, // source format pwfPCM, // destination format NULL, // no filter NULL, // no callback 0, // instance data (not used) ACM_STREAMOPENF_NONREALTIME); // flags if (mmr) { throw Exception("acmStreamOpen 失败 Src->PCM :"+IntToStr(mmr)); return(false); } int PCMSamples = DataLen * pwfPCM->nSamplesPerSec / wfSrc.nSamplesPerSec; int PCMDatalen = PCMSamples * pwfPCM->wBitsPerSample / 8; BYTE *PCMData = new BYTE [PCMDatalen]; // memset(pDst1Data, 0, dwDst1Bytes); ACMSTREAMHEADER strhdr; memset(&strhdr, 0, sizeof(ACMSTREAMHEADER)); strhdr.cbStruct = sizeof(ACMSTREAMHEADER); strhdr.pbSrc = Data; strhdr.cbSrcLength = DataLen; strhdr.pbDst = PCMData; strhdr.cbDstLength = PCMDatalen; mmr = acmStreamPrepareHeader(hstr, &strhdr, 0); mmr = acmStreamConvert(hstr, &strhdr, 0); if (mmr) { throw Exception("acmStreamConvert 失败 Src->PCM :"+IntToStr(mmr)); return(false); } acmStreamClose(hstr, 0); */ //PCM->Drv // DWORD DrvDatalen = pwfDrv->nAvgBytesPerSec * PCMSamples / pwfPCM->nSamplesPerSec; // DrvDatalen = DrvDatalen * 3 / 2; // add a little room // BYTE *DrvData = new BYTE [DrvDatalen]; MMRESULT mmr; memset(&sHeadPCM_TRUESPEECH, 0, sizeof(ACMSTREAMHEADER)); sHeadPCM_TRUESPEECH.cbStruct = sizeof(ACMSTREAMHEADER); sHeadPCM_TRUESPEECH.pbSrc = Data; // the source data to convert sHeadPCM_TRUESPEECH.cbSrcLength = DataLen; sHeadPCM_TRUESPEECH.cbSrcLengthUsed = DataLen; sHeadPCM_TRUESPEECH.pbDst = Data; sHeadPCM_TRUESPEECH.cbDstLength = DataLen; mmr = acmStreamPrepareHeader(sPCM_TRUESPEECH, &sHeadPCM_TRUESPEECH, 0); if(mmr!=MMSYSERR_NOERROR) return(false); // if(!CheckError(mmr,"acmStreamPrepareHeader 失败 PCM->Drv")) // return(false); mmr = acmStreamConvert(sPCM_TRUESPEECH, &sHeadPCM_TRUESPEECH, 0); if(mmr!=MMSYSERR_NOERROR) return(false); // if(!CheckError(mmr,"acmStreamConvert 失败 PCM->Drv")) // return(false); DataLen=sHeadPCM_TRUESPEECH.cbDstLengthUsed; return(true); } bool TACMConvert::UnCompress(BYTE *Data,int DataLen) { //解压 UncmpLen=0; MMRESULT mmr; memset(&sHeadTRUESPEECH_PCM, 0, sizeof(ACMSTREAMHEADER)); sHeadTRUESPEECH_PCM.cbStruct = sizeof(ACMSTREAMHEADER); sHeadTRUESPEECH_PCM.pbSrc = Data; sHeadTRUESPEECH_PCM.cbSrcLength = DataLen; sHeadTRUESPEECH_PCM.cbSrcLengthUsed = DataLen; sHeadTRUESPEECH_PCM.pbDst = UncmpData; // the source data to convert sHeadTRUESPEECH_PCM.cbDstLength = SamplesPerSec * BitsPerSample/4; mmr = acmStreamPrepareHeader(sTRUESPEECH_PCM, &sHeadTRUESPEECH_PCM, 0); if(mmr!=MMSYSERR_NOERROR) return(false); // if(!CheckError(mmr,"acmStreamPrepareHeader 失败 Drv->PCM")) // return(false); mmr = acmStreamConvert(sTRUESPEECH_PCM, &sHeadTRUESPEECH_PCM, 0); if(mmr!=MMSYSERR_NOERROR) return(false); // if(!CheckError(mmr,"acmStreamConvert 失败 Drv->PCM")) // return(false); UncmpLen=sHeadTRUESPEECH_PCM.cbDstLengthUsed; return(true); } /* bool TACMConvert::CheckError(MMRESULT mmr,AnsiString Prompt) { switch(mmr) { case 0: return(true); case ACMERR_BUSY: DebugMsg->Add(Prompt+" ACMERR_BUSY"); return(false); //The stream header specified in pash is currently in use and cannot be reused. case ACMERR_UNPREPARED: DebugMsg->Add(Prompt+" ACMERR_UNPREPARED"); return(false); // The stream header specified in pash is currently not prepared by the acmStreamPrepareHeader function. case MMSYSERR_INVALFLAG: DebugMsg->Add(Prompt+" MMSYSERR_INVALFLAG"); return(false); // At least one flag is invalid. case MMSYSERR_INVALHANDLE: DebugMsg->Add(Prompt+" MMSYSERR_INVALHANDLE"); return(false); // The specified handle is invalid. case MMSYSERR_INVALPARAM: DebugMsg->Add(Prompt+" MMSYSERR_INVALPARAM"); return(false); case MMSYSERR_NOMEM : DebugMsg->Add(Prompt+" MMSYSERR_NOMEM"); return(false); default : DebugMsg->Add(Prompt+" "+IntToStr(mmr)); return(false); } } */ bool TACMConvert::GetDriverFormat(WORD wFormatTag,WAVEFORMATEX *pwf) { memset(pwf, 0, MaxFromatSize); pwf->cbSize = MaxFromatSize - sizeof(WAVEFORMATEX); pwf->wFormatTag = wFormatTag; ACMFORMATDETAILS fd; memset(&fd, 0, sizeof(fd)); fd.cbStruct = sizeof(ACMFORMATDETAILS); fd.pwfx = pwf; fd.cbwfx = MaxFromatSize; fd.dwFormatTag = wFormatTag; // set up a struct to control the enumeration FIND_DRIVER_INFO fdi; fdi.ACMConvert=this; fdi.hadid = NULL; fdi.wFormatTag = wFormatTag; MMRESULT mmr = acmFormatEnum(ACMDrv, &fd, find_format_enum, (DWORD)(VOID*)&fdi, 0); if ((fdi.hadid == NULL) || mmr) return(false); return(true); } BOOL CALLBACK find_format_enum(HACMDRIVERID hadid, LPACMFORMATDETAILS pafd, DWORD dwInstance, DWORD fdwSupport) { FIND_DRIVER_INFO* pdi = (FIND_DRIVER_INFO*) dwInstance; if (pafd->dwFormatTag == (DWORD)pdi->wFormatTag) { // found it pdi->hadid = hadid; return FALSE; // stop enumerating } return TRUE; // continue enumerating } BOOL CALLBACK find_driver_enum(HACMDRIVERID hadid, DWORD dwInstance, DWORD fdwSupport) { FIND_DRIVER_INFO* pdi = (FIND_DRIVER_INFO*) dwInstance; // open the driver HACMDRIVER had = NULL; MMRESULT mmr = acmDriverOpen(&had, hadid, 0); if (mmr) { // some error return FALSE; // stop enumerating } // enumerate the formats it supports DWORD dwSize = 0; mmr = acmMetrics((HACMOBJ)had, ACM_METRIC_MAX_SIZE_FORMAT, &dwSize); if (dwSize < sizeof(WAVEFORMATEX)) dwSize = sizeof(WAVEFORMATEX); // for MS-PCM WAVEFORMATEX* pwf = (WAVEFORMATEX*) malloc(dwSize); memset(pwf, 0, dwSize); pwf->cbSize = LOWORD(dwSize) - sizeof(WAVEFORMATEX); pwf->wFormatTag = pdi->wFormatTag; ACMFORMATDETAILS fd; memset(&fd, 0, sizeof(fd)); fd.cbStruct = sizeof(fd); fd.pwfx = pwf; fd.cbwfx = dwSize; fd.dwFormatTag = pdi->wFormatTag; mmr = acmFormatEnum(had, &fd, find_format_enum, (DWORD)(VOID*)pdi, 0); free(pwf); acmDriverClose(had, 0); if (pdi->hadid || mmr) { // found it or some error return FALSE; // stop enumerating } return TRUE; // continue enumeration }