音频压缩代码集锦···
// conv.cpp
//
// convert a PCM wave to some other format
//转换一个PCM格式的wav到其他格式
#include <windows.h> //包含头文件 windows.h
#include <mmsystem.h>//包含头文件mmsystem.h
#include <mmreg.h> // Multimedia registration多媒体注册
#include <msacm.h> // Audio Compression Manager音频压缩管理器
#include <stdio.h>
#include <math.h>
// Locate a driver that supports a given format and return its ID
//寻找一个支持给定格式的驱动并返回其ID
typedef struct
{
HACMDRIVERID hadid;//指向HACMDRIVERID的句柄
WORD wFormatTag;//32位无符号整型 格式标签
} FIND_DRIVER_INFO;//结构FIND_DRIVER_INFO包含2个元素:HACMDRIVERID hadid 和WORD wFormatTag
// callback function for format enumeration
//用来枚举格式的回调函数
BOOL CALLBACK find_format_enum(HACMDRIVERID hadid, LPACMFORMATDETAILS pafd, DWORD dwInstance, DWORD fdwSupport)//LPACMFORMATDETAILS pafd指向ACM格式详情的指针
{
FIND_DRIVER_INFO* pdi = (FIND_DRIVER_INFO*) dwInstance;//FIND_DRIVER_INFO类型的指针 指向驱动信息
if (pafd->dwFormatTag == (DWORD)pdi->wFormatTag) {//如果详情中的格式标签==驱动信息指针pdi中的格式标签
// found it如果能找到
pdi->hadid = hadid;
return FALSE; // stop enumerating停止枚举
}
return TRUE; // continue enumerating继续枚举
}
// callback function for driver enumeration
//用来枚举驱动的回调函数
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;//HACMDRIVER类型的变量 had 指向ACM驱动的句柄
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继续枚举
}
// locate the first driver that supports a given format tag
//寻找支持给定格式标签的第一个驱动
HACMDRIVERID find_driver(WORD wFormatTag)
{
FIND_DRIVER_INFO fdi;
fdi.hadid = NULL;
fdi.wFormatTag = wFormatTag;
MMRESULT mmr = acmDriverEnum(find_driver_enum, (DWORD)(VOID*)&fdi, 0);
if (mmr) return NULL;
return fdi.hadid;
}
// get a description of the first format supported for a given tag
//获取驱动的描述 这个驱动是第一个支持给定标签的驱动。
WAVEFORMATEX* get_driver_format(HACMDRIVERID hadid, WORD wFormatTag)
{
// open the driver打开驱动
HACMDRIVER had = NULL;
MMRESULT mmr = acmDriverOpen(&had, hadid, 0);
if (mmr)
{
return NULL;
}
// allocate a structure for the info
//为信息分配一个结构
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 = wFormatTag;
ACMFORMATDETAILS fd;
memset(&fd, 0, sizeof(fd));
fd.cbStruct = sizeof(fd);
fd.pwfx = pwf;
fd.cbwfx = dwSize;
fd.dwFormatTag = wFormatTag;
// set up a struct to control the enumeration
//建立一个结构用于控制枚举
FIND_DRIVER_INFO fdi;
fdi.hadid = NULL;
fdi.wFormatTag = wFormatTag;
mmr = acmFormatEnum(had, &fd, find_format_enum, (DWORD)(VOID*)&fdi, 0);
acmDriverClose(had, 0);
if ((fdi.hadid == NULL) || mmr)
{
free(pwf);
return NULL;
}
return pwf;
}
int main(int argc, char* argv[])
{
// First we create a wave that might have been just recorded.
//首先我们建立一个也许是刚刚录制完毕的wave
// The format is 11.025 kHz, 8 bit mono PCM which is a recording
//它的格式是11.025 kHz,8位 单声道PCM
// format available on all machines.
//它是一种在所有机器上都有效的录音格式
// our sample wave will be 1 second long and will be a sine wave
//我们的wave样本是长度为一秒的正弦波,频率是1kHz,刚好1000个周期
// of 1kHz which is exactly 1,000 cycles
WAVEFORMATEX wfSrc;
memset(&wfSrc, 0, sizeof(wfSrc));
wfSrc.cbSize = 0;
wfSrc.wFormatTag = WAVE_FORMAT_PCM; // pcm
wfSrc.nChannels = 1; // mono单声道
wfSrc.nSamplesPerSec = 11025; // 11.025 kHz
wfSrc.wBitsPerSample = 8; // 8 bit
wfSrc.nBlockAlign = wfSrc.nChannels * wfSrc.wBitsPerSample / 8;
wfSrc.nAvgBytesPerSec = wfSrc.nSamplesPerSec * wfSrc.nBlockAlign;
DWORD dwSrcSamples = wfSrc.nSamplesPerSec;
BYTE* pSrcData = new BYTE [dwSrcSamples]; // 1 second duration
BYTE* pData = pSrcData;
double f = 1000.0;
double pi = 4.0 * atan(1.0);
double w = 2.0 * pi * f;
for (DWORD dw = 0; dw < dwSrcSamples; dw++)
{
double t = (double) dw / (double) wfSrc.nSamplesPerSec;
*pData++ = 128 + (BYTE)(127.0 * sin(w * t));
}
// Select a format to convert to选择一个要转换的格式
//WORD wFormatTag = WAVE_FORMAT_ADPCM;
//WORD wFormatTag = WAVE_FORMAT_IMA_ADPCM;
//WORD wFormatTag = WAVE_FORMAT_GSM610;
//WORD wFormatTag = WAVE_FORMAT_ALAW;
//WORD wFormatTag = WAVE_FORMAT_MULAW;
//WORD wFormatTag = 0x32; // MSN
WORD wFormatTag = WAVE_FORMAT_DSPGROUP_TRUESPEECH;
// Now we locate a CODEC that supports the destination format tag
//现在我们选取一个支持目标格式的编码器(CODEC)
HACMDRIVERID hadid = find_driver(wFormatTag);
if (hadid == NULL)
{
printf("No driver found\n");
exit(1);
}
printf("Driver found (hadid: %4.4lXH)\n", hadid);
// show some information about the driver
//显示这个驱动的一些信息
ACMDRIVERDETAILS dd;
dd.cbStruct = sizeof(dd);
MMRESULT mmr = acmDriverDetails(hadid, &dd, 0);
printf(" Short name: %s\n", dd.szShortName);
printf(" Long name: %s\n", dd.szLongName);
printf(" Copyright: %s\n", dd.szCopyright);
printf(" Licensing: %s\n", dd.szLicensing);
printf(" Features: %s\n", dd.szFeatures);
// get the details of the format取得格式的详情
// Note: this is just the first of one or more possible formats for the given tag
//注意:也许有多个目标格式支持给定的格式,而这只是第一个。
WAVEFORMATEX* pwfDrv = get_driver_format(hadid, wFormatTag);
if (pwfDrv == NULL) {
printf("Error getting format info\n");
exit(1);
}
printf("Driver format: %u bits, %lu samples per second\n", pwfDrv->wBitsPerSample, pwfDrv->nSamplesPerSec);
// get a PCM format tag the driver supports
//取得一个驱动支持的PCM格式标签
// Note: we just pick the first supported PCM format which might not really
//注意:我们只是选取了第一个支持PCM格式的,也许这个不是最好的选择。
// be the best choice.
WAVEFORMATEX* pwfPCM = get_driver_format(hadid, WAVE_FORMAT_PCM);
if (pwfPCM == NULL) {
printf("Error getting PCM format info\n");
exit(1);
}
printf("PCM format: %u bits, %lu samples per second\n", pwfPCM->wBitsPerSample, pwfPCM->nSamplesPerSec);
////////////////////////////////////////////////////////////////////////////////
// convert the source wave to the PCM format supported by the CODEC
//转换源wave到编码器支持的PCM格式
// we use any driver that can do the PCM to PCM conversion
//我们使用任何可以完成PCM到PCM转换的驱动
HACMSTREAM hstr = NULL;
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)
{
printf("Failed to open a stream to do PCM to PCM conversion\n");
exit(1);
}
// allocate a buffer for the result of the conversion.
//为转换结果分配缓存
DWORD dwSrcBytes = dwSrcSamples * wfSrc.wBitsPerSample / 8;
DWORD dwDst1Samples = dwSrcSamples * pwfPCM->nSamplesPerSec / wfSrc.nSamplesPerSec;
DWORD dwDst1Bytes = dwDst1Samples * pwfPCM->wBitsPerSample / 8;
BYTE* pDst1Data = new BYTE [dwDst1Bytes];
#ifdef _DEBUG
// fill the dest buffer with zeroes just so we can see if anything got
//
// converted in the debugger
memset(pDst1Data, 0, dwDst1Bytes);
#endif
// fill in the conversion info
ACMSTREAMHEADER strhdr;
memset(&strhdr, 0, sizeof(strhdr));
strhdr.cbStruct = sizeof(strhdr);
strhdr.pbSrc = pSrcData; // the source data to convert
strhdr.cbSrcLength = dwSrcBytes;
strhdr.pbDst = pDst1Data;
strhdr.cbDstLength = dwDst1Bytes;
// prep the header
mmr = acmStreamPrepareHeader(hstr, &strhdr, 0);
// convert the data
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");
// close the stream
acmStreamClose(hstr, 0);
///////////////////////////////////////////////////////////////////////////////////
// convert the intermediate PCM format to the final format
// open the driver
HACMDRIVER had = NULL;
mmr = acmDriverOpen(&had, hadid, 0);
if (mmr)
{
printf("Failed to open driver\n");
exit(1);
}
// open the conversion stream
// Note the use of the ACM_STREAMOPENF_NONREALTIME flag. Without this
// some software compressors will report error 512 - not possible
mmr = acmStreamOpen(&hstr,
had, // 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)
{
printf("Failed to open a stream to do PCM to driver format conversion\n");
exit(1);
}
// allocate a buffer for the result of the conversion.为转换结果分配一个缓冲
// compute the output buffer size based on the average byte rate基于平均字节率来计算输出缓冲区的大小
// and add a bit for randomness
// the IMA_ADPCM driver fails the conversion without this extra space
DWORD dwDst2Bytes = pwfDrv->nAvgBytesPerSec * dwDst1Samples / pwfPCM->nSamplesPerSec;
dwDst2Bytes = dwDst2Bytes * 3 / 2; // add a little room增加一点空间
BYTE* pDst2Data = new BYTE [dwDst2Bytes];
#ifdef _DEBUG
// fill the dest buffer with zeroes just so we can see if anything got
// converted in the debugger用0填充目标缓冲,由此我们可以在调试中看到转换了的东西
memset(pDst2Data, 0, dwDst2Bytes);
#endif
// fill in the conversion info填充转换信息
ACMSTREAMHEADER strhdr2;
memset(&strhdr2, 0, sizeof(strhdr2));
strhdr2.cbStruct = sizeof(strhdr2);
strhdr2.pbSrc = pDst1Data; // the source data to convert
strhdr2.cbSrcLength = dwDst1Bytes;
strhdr2.pbDst = pDst2Data;
strhdr2.cbDstLength = dwDst2Bytes;
// prep the header准备wav头
mmr = acmStreamPrepareHeader(hstr, &strhdr2, 0);
// convert the data
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");
// close the stream and driver关闭流和驱动
mmr = acmStreamClose(hstr, 0);
mmr = acmDriverClose(had, 0);
// show the conversion stats显示转换状态
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);
return 0;
}