我用录音机录了一段声音,从属性对话框获得它的格式为PCM,平均数据速率为176.400kb/s,采样速率为44.100KHz,16位双声道,那么我用ACM进行压缩是的源数据格式应该如何获取呢?
直接写:
WAVEFORMATEX wfSrc;
memset(&wfSrc, 0, sizeof(wfSrc));
wfSrc.cbSize = 0;
wfSrc.wFormatTag = WAVE_FORMAT_PCM; // PCM
wfSrc.nChannels = 2;
wfSrc.nSamplesPerSec = 44100;
wfSrc.wBitsPerSample = 16;
wfSrc.nBlockAlign = wfSrc.nChannels * wfSrc.wBitsPerSample / 8;
wfSrc.nAvgBytesPerSec = wfSrc.nSamplesPerSec * wfSrc.nBlockAlign;
DWORD dwSrcSamples = wfSrc.nSamplesPerSec;
还是需要用一些Multimedie I/O函数如:mmioOpen,mmioRead?还有,如果我用Microsoft G.723.1 CODEC进行压缩,它的信息如下:
different format conversions
Short name: Microsoft G.723.1
Long name: Microsoft G.723.1 CODEC
Copyright: 版权所有 (C) 1996 Intel Corporation and Microsoft Corporation
Licensing:
Features: 压缩和解压缩 G.723.1 音频数据。
Supports 2 formats
Supports 0 filter formats
0001H, 11.025 kHz, 16 位, 单声道
0001H, 8.000 kHz, 16 位, 单声道
0042H, 8 千赫兹单声道,6400 位/秒
0042H, 8 千赫兹单声道,5333 位/秒那么用上述源数据进行压缩后的目标格式G.723.1又是如何获取和表示呢?
MSDN和网上始终找不到相关范例和格式说明,困惑啊。
直接写:
WAVEFORMATEX wfSrc;
memset(&wfSrc, 0, sizeof(wfSrc));
wfSrc.cbSize = 0;
wfSrc.wFormatTag = WAVE_FORMAT_PCM; // PCM
wfSrc.nChannels = 2;
wfSrc.nSamplesPerSec = 44100;
wfSrc.wBitsPerSample = 16;
wfSrc.nBlockAlign = wfSrc.nChannels * wfSrc.wBitsPerSample / 8;
wfSrc.nAvgBytesPerSec = wfSrc.nSamplesPerSec * wfSrc.nBlockAlign;
DWORD dwSrcSamples = wfSrc.nSamplesPerSec;
还是需要用一些Multimedie I/O函数如:mmioOpen,mmioRead?还有,如果我用Microsoft G.723.1 CODEC进行压缩,它的信息如下:
different format conversions
Short name: Microsoft G.723.1
Long name: Microsoft G.723.1 CODEC
Copyright: 版权所有 (C) 1996 Intel Corporation and Microsoft Corporation
Licensing:
Features: 压缩和解压缩 G.723.1 音频数据。
Supports 2 formats
Supports 0 filter formats
0001H, 11.025 kHz, 16 位, 单声道
0001H, 8.000 kHz, 16 位, 单声道
0042H, 8 千赫兹单声道,6400 位/秒
0042H, 8 千赫兹单声道,5333 位/秒那么用上述源数据进行压缩后的目标格式G.723.1又是如何获取和表示呢?
MSDN和网上始终找不到相关范例和格式说明,困惑啊。
CFile cf("c:\\1.wav",CFile::modeRead);
cf.Seek(20,CFile::begin);
WAVEFORMATEX wfSrc;
cf.Read(&wfSrc,sizeof(wfSrc));
cf.Close();
目标格式:
你先acmDriverEnum,在YourDriverEnumFunc中根据HACMDRIVERID hadid;调用acmDriverOpen
HACMDRIVER had = 0;
acmDriverOpen(&had, hadid, 0);
再调用acmMetrics
DWORD dwSize = 0;
acmMetrics((HACMOBJ)had, ACM_METRIC_MAX_SIZE_FORMAT, &dwSize);
再acmFormatEnum
WAVEFORMATEX* pwf = (WAVEFORMATEX*) malloc(dwSize);
memset(pwf, 0, dwSize);
pwf->cbSize = LOWORD(dwSize) - sizeof(WAVEFORMATEX);
pwf->wFormatTag = WAVE_FORMAT_UNKNOWN;
ACMFORMATDETAILS fd = {sizeof(fd)};
fd.pwfx = pwf;
fd.cbwfx = dwSize;
fd.dwFormatTag = WAVE_FORMAT_UNKNOWN;
acmFormatEnum(had, &fd, YourFormatEnumProc, 0, 0);
YourFormatEnumProc里可以得到所支持的格式
// test4.cpp : 定义控制台应用程序的入口点。
//#include "stdafx.h"
#include "test4.h"
#include "conio.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
// 唯一的应用程序对象CWinApp theApp;
WAVEFORMATEX *pwfPCM;
typedef struct {
HACMDRIVERID hadid;
WORD wFormatTag;
WAVEFORMATEX *pwfSupport;
} FIND_DRIVER_INFO;using namespace std;/* ********************************************* */
// CODEC支持格式枚举回调函数
BOOL CALLBACK FormatEnumProc(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;
// pdi->pwfSupport = pafd->pwfx;
return FALSE; // stop enumerating
}
// printf(" %4.4lXH, %s\n", pafd->dwFormatTag, pafd->szFormat);
return 1;
// return TRUE; // 继续枚举
}BOOL CALLBACK FormatEnumProc2(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->pwfSupport = pafd->pwfx;
return FALSE; // stop enumerating
}
// printf(" %4.4lXH, %s\n", pafd->dwFormatTag, pafd->szFormat);
return 1;
// return TRUE; // 继续枚举
}/* ********************************************* */
// CODEC枚举回调函数
BOOL CALLBACK DriverEnumProc(HACMDRIVERID hadid, DWORD dwInstance, DWORD fdwSupport)
{
FIND_DRIVER_INFO* pdi = (FIND_DRIVER_INFO*) dwInstance;
// printf("Driver found (hadid: %4.4lXH)\n", hadid);
HACMDRIVER had = NULL;
MMRESULT mmr = acmDriverOpen(&had, hadid, 0);
// ACMDRIVERDETAILS dd;
// dd.cbStruct = sizeof(dd);
// mmr = acmDriverDetails(hadid, &dd, 0);
// if(!mmr)
// {
// printf(" Long name: %s\n", dd.szLongName);
// getch();
// }
//////////////////////////////////////////////////////////////////////////////////
// 以下为CODEC格式枚举入口 DWORD dwSize = 0;
mmr = acmMetrics((HACMOBJ)had, ACM_METRIC_MAX_SIZE_FORMAT, &dwSize);
// pwfDrv->wFormatTag = WAVE_FORMAT_UNKNOWN;
if (dwSize < sizeof(WAVEFORMATEX)) dwSize = sizeof(WAVEFORMATEX); // for MS-PCM
WAVEFORMATEX* pwf = (WAVEFORMATEX*) malloc(dwSize);
memset(pwf, 0, dwSize);
WORD pcbSize = LOWORD(dwSize) - sizeof(WAVEFORMATEX);
pwf->cbSize = pcbSize;
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, FormatEnumProc, (DWORD)(VOID*)pdi, 0);
free(pwf);//////////////////////////////////////////////////////////////////////////////////
acmDriverClose(had, 0);
if (pdi->hadid || mmr) {
// found it or some error
return FALSE; // stop enumerating
}
return 1;
}HACMDRIVERID find_driver(WORD wFormatTag)
{
FIND_DRIVER_INFO fdi;
fdi.hadid = NULL;
fdi.wFormatTag = wFormatTag;
MMRESULT mmr = acmDriverEnum(DriverEnumProc, (DWORD)(VOID*)&fdi, 0);
if (mmr) return NULL;
return fdi.hadid;
}WAVEFORMATEX* get_driver_format(HACMDRIVERID hadid,WORD wFormatTag)
{
FIND_DRIVER_INFO fdi;
fdi.hadid = hadid ;
fdi.wFormatTag = wFormatTag;
HACMDRIVER had = NULL;
MMRESULT mmr = acmDriverOpen(&had, hadid, 0);
//////////////////////////////////////////////////////////////////////////////////
// 以下为CODEC格式枚举入口 DWORD dwSize = 0;
mmr = acmMetrics((HACMOBJ)had, ACM_METRIC_MAX_SIZE_FORMAT, &dwSize);
// pwfDrv->wFormatTag = WAVE_FORMAT_UNKNOWN;
if (dwSize < sizeof(WAVEFORMATEX)) dwSize = sizeof(WAVEFORMATEX); // for MS-PCM
WAVEFORMATEX* pwf = (WAVEFORMATEX*) malloc(dwSize);
memset(pwf, 0, dwSize);
WORD pcbSize = LOWORD(dwSize) - sizeof(WAVEFORMATEX);
pwf->cbSize = pcbSize;
pwf->wFormatTag = fdi.wFormatTag;
ACMFORMATDETAILS fd;
memset(&fd, 0, sizeof(fd));
fd.cbStruct = sizeof(fd);
fd.pwfx = pwf;
fd.cbwfx = dwSize;
fd.dwFormatTag = fdi.wFormatTag;
mmr = acmFormatEnum(had, &fd, FormatEnumProc2, (DWORD)(VOID*)&fdi, 0);
free(pwf);//////////////////////////////////////////////////////////////////////////////////
acmDriverClose(had, 0);
if (mmr) {
// found it or some error
return FALSE; // stop enumerating
}
return fdi.pwfSupport;
}
{
int nRetCode = 0; // 初始化 MFC 并在失败时显示错误
if (!AfxWinInit(::GetModuleHandle(NULL), NULL, ::GetCommandLine(), 0))
{
// TODO: 更改错误代码以符合您的需要
_tprintf(_T("致命错误:MFC 初始化失败\n"));
nRetCode = 1;
}
else
{
// TODO: 在此处为应用程序的行为编写代码。
WORD wFormatTag=WAVE_FORMAT_MSG723;
// WORD wFormatTag=WAVE_FORMAT_DSPGROUP_TRUESPEECH;
HACMDRIVERID hadid=find_driver(wFormatTag);
if(hadid==NULL)
{
printf("No driver found\n");
// exit(1);
}
printf("Driver found (hadid:%4.4lXH)\n",hadid);
CFile cf("f:\\aa.wav",CFile::modeRead);
cf.Seek(20,CFile::begin);
WAVEFORMATEX pwfSrc;
cf.Read(&pwfSrc,sizeof(pwfSrc));
printf("%4.4lXH",pwfSrc.wFormatTag);
WAVEFORMATEX *pwfDrv=get_driver_format(hadid,wFormatTag);
WAVEFORMATEX *pwfPCM=get_driver_format(hadid,WAVE_FORMAT_PCM);
cf.Close();
DWORD dwSrcSamples = pwfSrc.nSamplesPerSec;
BYTE* pSrcData = new BYTE [dwSrcSamples];
BYTE* pData = pSrcData;//中间格式的转换过程 // 获取驱动程序所支持的PCM格式标签
/////////////////////////////////////////////////////////////////////////////
// 将源wave转换为CODEC所支持的PCM格式
// 我们使用任一种能实现PCM格式间转换驱动程序
HACMSTREAM hstr = NULL;
MMRESULT mmr = acmStreamOpen(&hstr,
NULL, // 任一驱动程序
&pwfSrc, // 源格式
pwfDrv, // 目标格式
NULL, // 无过滤
NULL, // 没回调
0, // 实例数据(未使用)
ACM_STREAMOPENF_NONREALTIME); // 标志
if (mmr) {
printf("Failed to open a stream to do PCM to PCM conversion\n");
// exit(1);
}
// 为转换结果开辟一个缓冲区 DWORD dwSrcBytes = pwfSrc.wBitsPerSample*dwSrcSamples / 8;
DWORD dwDst1Samples = pwfPCM->nSamplesPerSec*dwSrcSamples / pwfSrc.nSamplesPerSec;
DWORD dwDst1Bytes = dwDst1Samples * pwfPCM->wBitsPerSample / 8;
BYTE* pDst1Data = new BYTE [dwDst1Bytes]; // 填写转换信息
ACMSTREAMHEADER strhdr;
memset(&strhdr, 0, sizeof(strhdr));
strhdr.cbStruct = sizeof(strhdr);
strhdr.pbSrc = pSrcData; // 要转换的源数据
strhdr.cbSrcLength = dwSrcBytes;
strhdr.pbDst = pDst1Data;
strhdr.cbDstLength = dwDst1Bytes; // 准备好头
mmr = acmStreamPrepareHeader(hstr, &strhdr, 0); // 转换数据
printf("Converting to intermediate PCM format...\n");
mmr = acmStreamConvert(hstr, &strhdr, 0);
if (mmr) {
printf("Failed to do PCM to PCM conversion\n");
// exit(1);
}
printf("Converted OK\n");
// 关闭流
acmStreamClose(hstr, 0); ///////////////////////////////////////////////////////////////////////////////////
// 将中间格式转换为最终的压缩格式
// 打开驱动程序 HACMDRIVER had = NULL;
mmr = acmDriverOpen(&had, hadid, 0);
if (mmr) {
printf("Failed to open driver\n");
// exit(1);
}
// 打开转换流
// 注意使用了ACM_STREAMOPENF_NONREALTIME标志.
// 没有此标志一些软件压缩程序会报告512号错误--即不可能 mmr = acmStreamOpen(&hstr,
NULL, // 驱动程序句柄
pwfPCM, // 源格式
pwfDrv, // 目标格式
NULL, // 不过滤
NULL, // 无回调函数
0, // 实例数据(未使用)
ACM_STREAMOPENF_NONREALTIME); // 标志
if (mmr) {
printf("Failed to open a stream to do PCM to driver format conversion\n");
// exit(1);
}
// 为转换结果分配一个缓冲区
// 根据以字节计的平均速率计算输出缓冲区的尺寸
// 并加上一机动位(bit)
// 没有此额外的空间IMA_ADPCM驱动程序将不能转换
DWORD dwDst2Bytes = pwfDrv->nAvgBytesPerSec * dwDst1Samples / pwfPCM->nSamplesPerSec;
pwfPCM->nSamplesPerSec;
dwDst2Bytes = dwDst2Bytes * 3 / 2; // 增加一点空间
BYTE* pDst2Data = new BYTE [dwDst2Bytes]; // 填写转换信息
ACMSTREAMHEADER strhdr2;
memset(&strhdr2, 0, sizeof(strhdr2));
strhdr2.cbStruct = sizeof(strhdr2);
strhdr2.pbSrc = pSrcData; // 要转换的源数据
strhdr2.cbSrcLength = dwDst1Bytes;
strhdr2.pbDst = pDst2Data;
strhdr2.cbDstLength = dwDst2Bytes; // 准备头
mmr = acmStreamPrepareHeader(hstr, &strhdr2, 0); // 转换数据
printf("Converting to final format...\n");
mmr = acmStreamConvert(hstr, &strhdr2, 0);
if (mmr) {
printf("Failed to do PCM to driver format conversion\n");
// exit(1);
}
printf("Converted OK\n");
// 关闭流及驱动程序
mmr = acmStreamClose(hstr, 0);
mmr = acmDriverClose(had, 0);
// 显示转换统计结果
printf("Source wave had %lu bytes\n", dwSrcBytes);
printf("Converted wave has %lu bytes\n", strhdr2.cbDstLengthUsed);
printf("Compression ratio is %f\n", (double) dwSrcBytes /
(double) strhdr2.cbDstLengthUsed);
acmDriverClose(had, 0); getch();
}
return nRetCode;
}
/////////////////////////////////////////////////////////////////////////////
// 将源wave转换为CODEC所支持的PCM格式
// 我们使用任一种能实现PCM格式间转换驱动程序
HACMSTREAM hstr = NULL;
MMRESULT mmr = acmStreamOpen(&hstr,
NULL, // 任一驱动程序
&pwfSrc, // 源格式
pwfDrv, // 目标格式
NULL, // 无过滤
NULL, // 没回调
0, // 实例数据(未使用)
ACM_STREAMOPENF_NONREALTIME); // 标志
if (mmr) {
/* ******************************************************************* */
//提示下面这一句
/* ******************************************************************* */
printf("Failed to open a stream to do PCM to PCM conversion\n");
// exit(1);
}