我用录音机录了一段声音,从属性对话框获得它的格式为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和网上始终找不到相关范例和格式说明,困惑啊。

解决方案 »

  1.   

    从文件读取格式:
    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里可以得到所支持的格式
      

  2.   

    如何读取数据到缓冲中,用mmioWrite行吗?我下面的程序在第一个acmStreamOpen就提示流打开失败,应该是没有都缓冲的原因。
    // 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;
    }
      

  3.   

    int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
    {
    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;
    }
      

  4.   

    编译是通过的,执行时问题出在main函数里// 获取驱动程序所支持的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); 
    }