conv.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394
  1. // conv.cpp
  2. //
  3. // convert a PCM wave to some other format
  4. //转换一个PCM格式的wav到其他格式
  5. #include "stdafx.h"
  6. #include <windows.h> //包含头文件 windows.h
  7. #include <mmsystem.h>//包含头文件mmsystem.h
  8. #include <mmreg.h> // Multimedia registration多媒体注册
  9. #include <msacm.h> // Audio Compression Manager音频压缩管理器
  10. #include <stdio.h>
  11. #include <math.h>
  12. #include "conv.h"
  13. #include "Global.h"
  14. #pragma comment(lib,"MSAcm32.Lib")
  15. #pragma comment(lib,"winmm.lib")
  16. // Locate a driver that supports a given format and return its ID
  17. //寻找一个支持给定格式的驱动并返回其ID
  18. typedef struct
  19. {
  20. HACMDRIVERID hadid;//指向HACMDRIVERID的句柄
  21. WORD wFormatTag;//32位无符号整型 格式标签
  22. } FIND_DRIVER_INFO;//结构FIND_DRIVER_INFO包含2个元素:HACMDRIVERID hadid 和WORD wFormatTag
  23. // callback function for format enumeration
  24. //用来枚举格式的回调函数
  25. BOOL CALLBACK find_format_enum(HACMDRIVERID hadid, LPACMFORMATDETAILS pafd, DWORD dwInstance, DWORD fdwSupport)//LPACMFORMATDETAILS pafd指向ACM格式详情的指针
  26. {
  27. FIND_DRIVER_INFO* pdi = (FIND_DRIVER_INFO*) dwInstance;//FIND_DRIVER_INFO类型的指针 指向驱动信息
  28. if (pafd->dwFormatTag == (DWORD)pdi->wFormatTag) //如果详情中的格式标签==驱动信息指针pdi中的格式标签
  29. {
  30. // found it如果能找到
  31. pdi->hadid = hadid;
  32. return FALSE; // stop enumerating停止枚举
  33. }
  34. return TRUE; // continue enumerating继续枚举
  35. }
  36. // callback function for driver enumeration
  37. //用来枚举驱动的回调函数
  38. BOOL CALLBACK find_driver_enum(HACMDRIVERID hadid, DWORD dwInstance, DWORD fdwSupport)
  39. {
  40. FIND_DRIVER_INFO* pdi = (FIND_DRIVER_INFO*) dwInstance;
  41. // open the driver打开驱动
  42. HACMDRIVER had = NULL;//HACMDRIVER类型的变量 had 指向ACM驱动的句柄
  43. MMRESULT mmr = acmDriverOpen(&had, hadid, 0);
  44. if (mmr)
  45. {
  46. // some error错误
  47. return FALSE; // stop enumerating停止枚举
  48. }
  49. // enumerate the formats it supports枚举它支持的格式
  50. DWORD dwSize = 0;
  51. mmr = acmMetrics((HACMOBJ)had, ACM_METRIC_MAX_SIZE_FORMAT, &dwSize);
  52. if (dwSize < sizeof(WAVEFORMATEX)) dwSize = sizeof(WAVEFORMATEX); // for MS-PCM
  53. WAVEFORMATEX* pwf = (WAVEFORMATEX*) malloc(dwSize);
  54. memset(pwf, 0, dwSize);
  55. pwf->cbSize = LOWORD(dwSize) - sizeof(WAVEFORMATEX);
  56. pwf->wFormatTag = pdi->wFormatTag;
  57. ACMFORMATDETAILS fd;
  58. memset(&fd, 0, sizeof(fd));
  59. fd.cbStruct = sizeof(fd);
  60. fd.pwfx = pwf;
  61. fd.cbwfx = dwSize;
  62. fd.dwFormatTag = pdi->wFormatTag;
  63. mmr = acmFormatEnum(had, &fd, find_format_enum, (DWORD)(VOID*)pdi, 0);
  64. free(pwf);
  65. acmDriverClose(had, 0);
  66. if (pdi->hadid || mmr)
  67. {
  68. // found it or some error找到了 或 有错误
  69. return FALSE; // stop enumerating停止枚举
  70. }
  71. return TRUE; // continue enumeration继续枚举
  72. }
  73. // locate the first driver that supports a given format tag
  74. //寻找支持给定格式标签的第一个驱动
  75. HACMDRIVERID find_driver(WORD wFormatTag)
  76. {
  77. FIND_DRIVER_INFO fdi;
  78. fdi.hadid = NULL;
  79. fdi.wFormatTag = wFormatTag;
  80. MMRESULT mmr = acmDriverEnum(find_driver_enum, (DWORD)(VOID*)&fdi, 0);
  81. if (mmr) return NULL;
  82. return fdi.hadid;
  83. }
  84. // get a description of the first format supported for a given tag
  85. //获取驱动的描述 这个驱动是第一个支持给定标签的驱动。
  86. WAVEFORMATEX* get_driver_format(HACMDRIVERID hadid, WORD wFormatTag)
  87. {
  88. // open the driver打开驱动
  89. HACMDRIVER had = NULL;
  90. MMRESULT mmr = acmDriverOpen(&had, hadid, 0);
  91. if (mmr) {
  92. return NULL;
  93. }
  94. // allocate a structure for the info
  95. //为信息分配一个结构
  96. DWORD dwSize = 0;
  97. mmr = acmMetrics((HACMOBJ)had, ACM_METRIC_MAX_SIZE_FORMAT, &dwSize);
  98. if (dwSize < sizeof(WAVEFORMATEX)) dwSize = sizeof(WAVEFORMATEX); // for MS-PCM
  99. WAVEFORMATEX* pwf = (WAVEFORMATEX*) malloc(dwSize);
  100. memset(pwf, 0, dwSize);
  101. pwf->cbSize = LOWORD(dwSize) - sizeof(WAVEFORMATEX);
  102. pwf->wFormatTag = wFormatTag;
  103. ACMFORMATDETAILS fd;
  104. memset(&fd, 0, sizeof(fd));
  105. fd.cbStruct = sizeof(fd);
  106. fd.pwfx = pwf;
  107. fd.cbwfx = dwSize;
  108. fd.dwFormatTag = wFormatTag;
  109. // set up a struct to control the enumeration
  110. //建立一个结构用于控制枚举
  111. FIND_DRIVER_INFO fdi;
  112. fdi.hadid = NULL;
  113. fdi.wFormatTag = wFormatTag;
  114. mmr = acmFormatEnum(had, &fd, find_format_enum, (DWORD)(VOID*)&fdi, 0);
  115. acmDriverClose(had, 0);
  116. if ((fdi.hadid == NULL) || mmr)
  117. {
  118. free(pwf);
  119. return NULL;
  120. }
  121. return pwf;
  122. }
  123. int PcmToALow(char *pFileName, char *pDescFileName)
  124. {
  125. FILE *fp,*fpCopy;
  126. MMRESULT mmr;
  127. HEADER *pPcmHEADER = new HEADER[sizeof(HEADER)];
  128. FMT *pPcmFMT = new FMT[sizeof(FMT)];
  129. DATA *pWaveHeaderData = new DATA[sizeof(DATA)];
  130. int nLen = sizeof(HEADER) + sizeof(FMT) + sizeof(DATA) + 2;
  131. int nReadNum;
  132. int nFileSize;
  133. if((fp = fopen(pFileName, "rb")) == NULL) //读取文件
  134. {
  135. return -1;
  136. }
  137. if((fpCopy = fopen(pDescFileName, "wb+")) == NULL) //为转换建立一个新文件
  138. {
  139. return -1;
  140. }
  141. fseek(fp, 0, SEEK_SET);
  142. fseek(fp, 0, SEEK_END);
  143. nFileSize = ftell(fp);
  144. fseek(fp, 0, SEEK_SET);
  145. fread(pPcmHEADER,sizeof(unsigned short), sizeof(HEADER), fp );
  146. DWORD nWaveFileSize = pPcmHEADER->dwSize;
  147. fseek(fp, sizeof(HEADER), SEEK_SET);
  148. fread( pPcmFMT, sizeof(unsigned short), sizeof(FMT), fp );
  149. fseek(fp, sizeof(HEADER) + sizeof(FMT) + 2, SEEK_SET); //注意,+2是跳过保留的两位
  150. fread(pWaveHeaderData,sizeof(unsigned short), sizeof(DATA), fp );
  151. DWORD nPcmDataSize = pWaveHeaderData->dwSize;
  152. BYTE* pSrcData = new BYTE [nFileSize - nLen]; // 1 second duration
  153. memset(pSrcData, 0, nFileSize - nLen);
  154. fseek(fp, nLen, SEEK_SET);
  155. //nReadNum = fread(pSrcData, sizeof(unsigned short), pWaveHeaderData->dwSize, fp);
  156. nReadNum = fread(pSrcData, 1, nFileSize - nLen, fp);
  157. if( nReadNum == 0 ) //读文件错误
  158. {
  159. return -1;
  160. }
  161. WAVEFORMATEX wfSrc;
  162. memset(&wfSrc, 0, sizeof(wfSrc));
  163. wfSrc.cbSize = pPcmFMT->dwSize;
  164. wfSrc.wFormatTag = pPcmFMT->wFormatTag; // pcm
  165. wfSrc.nChannels = pPcmFMT->wChannels; // mono单声道
  166. wfSrc.nSamplesPerSec = pPcmFMT->dwSamplesPerSec; // 8000 kHz
  167. wfSrc.wBitsPerSample = pPcmFMT->uiBitsPerSample; // 8 bit
  168. wfSrc.nBlockAlign = pPcmFMT->wBlockAlign;
  169. wfSrc.nAvgBytesPerSec = pPcmFMT->dwAvgBytesPerSec;
  170. // 选择一个要转换的格式
  171. WORD wFormatTag = WAVE_FORMAT_ALAW;
  172. //现在我们选取一个支持目标格式的编码器(CODEC)
  173. HACMDRIVERID hadid = find_driver(wFormatTag);
  174. if (hadid == NULL)
  175. {
  176. exit(1);
  177. }
  178. //显示这个驱动的一些信息
  179. ACMDRIVERDETAILS dd;
  180. dd.cbStruct = sizeof(dd);
  181. mmr = acmDriverDetails(hadid, &dd, 0);
  182. // 取得格式的详情
  183. //注意:也许有多个目标格式支持给定的格式,而这只是第一个。
  184. WAVEFORMATEX* pwfDrv = get_driver_format(hadid, wFormatTag);
  185. if (pwfDrv == NULL)
  186. {
  187. exit(1);
  188. }
  189. //取得一个驱动支持的PCM格式标签
  190. //注意:我们只是选取了第一个支持PCM格式的,也许这个不是最好的选择。
  191. WAVEFORMATEX* pwfPCM = get_driver_format(hadid, WAVE_FORMAT_PCM);
  192. if (pwfPCM == NULL)
  193. {
  194. exit(1);
  195. }
  196. ////////////////////////////////////////////////////////////////////////////////
  197. //转换源wave到编码器支持的PCM格式
  198. //我们使用任何可以完成PCM到PCM转换的驱动
  199. HACMSTREAM hstr = NULL;
  200. mmr = acmStreamOpen(&hstr,
  201. NULL, // 任意驱动
  202. &wfSrc, // 源格式
  203. pwfPCM, // 目标格式
  204. NULL, // 无过滤
  205. NULL, // 无回调
  206. 0, // 实例数据(未使用)
  207. ACM_STREAMOPENF_NONREALTIME); // flags
  208. if (mmr)
  209. {
  210. exit(1);
  211. }
  212. // 为转换结果开辟一个缓冲区
  213. int nFileData = (nFileSize - nLen) * 2 - 6000;
  214. BYTE* pDst1Data = new BYTE [nFileData]; // 填写转换信息
  215. memset(pDst1Data, 0, nFileData);
  216. // fill in the conversion info
  217. ACMSTREAMHEADER strhdr;
  218. memset(&strhdr, 0, sizeof(strhdr));
  219. strhdr.cbStruct = sizeof(strhdr);
  220. strhdr.pbSrc = pSrcData; // the source data to convert
  221. strhdr.cbSrcLength = nFileSize - nLen;
  222. strhdr.pbDst = pDst1Data;
  223. strhdr.cbDstLength = nFileData;
  224. // prep the header
  225. mmr = acmStreamPrepareHeader(hstr, &strhdr, 0);
  226. // convert the data
  227. mmr = acmStreamConvert(hstr, &strhdr, 0);
  228. if (mmr)
  229. {
  230. exit(1);
  231. }
  232. // close the stream
  233. acmStreamClose(hstr, 0);
  234. ///////////////////////////////////////////////////////////////////////////////////
  235. // 将中间格式转换为最终的压缩格式
  236. // 打开驱动程序
  237. HACMDRIVER had = NULL;
  238. mmr = acmDriverOpen(&had, hadid, 0);
  239. if (mmr)
  240. {
  241. exit(1);
  242. }
  243. // 打开转换流
  244. // 注意使用了ACM_STREAMOPENF_NONREALTIME标志.
  245. // 没有此标志一些软件压缩程序会报告512号错误--即不可能
  246. mmr = acmStreamOpen(&hstr,
  247. had, // driver handle
  248. pwfPCM, // source format
  249. pwfDrv, // destination format
  250. NULL, // no filter
  251. NULL, // no callback
  252. 0, // instance data (not used)
  253. ACM_STREAMOPENF_NONREALTIME); // flags
  254. if (mmr)
  255. {
  256. exit(1);
  257. }
  258. // 为转换结果分配一个缓冲区
  259. // 根据以字节计的平均速率计算输出缓冲区的尺寸
  260. // 并加上一机动位(bit)
  261. // 没有此额外的空间IMA_ADPCM驱动程序将不能转换
  262. DWORD dwDst2Bytes ;//= pwfDrv->nAvgBytesPerSec * dwDst1Bytes / pwfPCM->nSamplesPerSec;
  263. //dwDst2Bytes = (nFileSize - nLen) * 3 / 2; // 增加一点空间
  264. dwDst2Bytes = nFileSize - nLen; // 增加一点空间
  265. BYTE* pDst2Data = new BYTE [dwDst2Bytes];
  266. #ifdef _DEBUG
  267. // 用0填充目标缓冲,由此我们可以在调试中看到转换了的东西
  268. memset(pDst2Data, 0, dwDst2Bytes);
  269. #endif
  270. // 填充转换信息
  271. ACMSTREAMHEADER strhdr2;
  272. memset(&strhdr2, 0, sizeof(strhdr2));
  273. strhdr2.cbStruct = sizeof(strhdr2);
  274. strhdr2.pbSrc = pDst1Data; // the source data to convert
  275. strhdr2.cbSrcLength = nFileData;
  276. strhdr2.pbDst = pDst2Data;
  277. strhdr2.cbDstLength = dwDst2Bytes;
  278. // prep the header准备wav头
  279. mmr = acmStreamPrepareHeader(hstr, &strhdr2, 0);
  280. // convert the data
  281. mmr = acmStreamConvert(hstr, &strhdr2, 0);
  282. if (mmr)
  283. {
  284. exit(1);
  285. }
  286. fclose(fp);
  287. // close the stream and driver关闭流和驱动
  288. mmr = acmStreamClose(hstr, 0);
  289. mmr = acmDriverClose(had, 0);
  290. //生成转换完的ccitt格式文件
  291. fseek(fpCopy, 0, SEEK_SET);
  292. strcpy(pPcmHEADER->fccID,"RIFF");
  293. strcpy(pPcmHEADER->fccType,"WAVE");
  294. pPcmHEADER->dwSize = nWaveFileSize;
  295. fseek(fpCopy,sizeof(HEADER),1); //跳过HEADER的长度,以便下面继续写入wav文件的数据;
  296. pPcmFMT->dwSamplesPerSec = 8000;
  297. pPcmFMT->dwAvgBytesPerSec = 8000;//wfSrc.nAvgBytesPerSec;//pPcmFMT->dwSamplesPerSec * sizeof(DATA);
  298. pPcmFMT->uiBitsPerSample = 8;
  299. strcpy(pPcmFMT->fccID, "fmt ");
  300. pPcmFMT->dwSize = wfSrc.cbSize;
  301. pPcmFMT->wBlockAlign = wfSrc.nBlockAlign;
  302. pPcmFMT->wChannels = 1;
  303. pPcmFMT->wFormatTag = WAVE_FORMAT_ALAW;
  304. //以上是创建wav头的FMT;
  305. fwrite(pPcmFMT,sizeof(FMT),1,fpCopy); //将FMT写入.wav文件;
  306. WORD nExBit = 0;
  307. fwrite(&nExBit,2, 1, fpCopy);
  308. //写入保留两位字节
  309. //以下是创建wav头的DATA; 但由于DATA.dwsize未知所以不能写入.wav文件
  310. strcpy(pWaveHeaderData->fccID,"data");
  311. //以上是创建wav头的DATA;
  312. // fwrite(&pcmDATA,sizeof(DATA),1,fpCpy);
  313. pWaveHeaderData->dwSize = nPcmDataSize; //给pcmDATA.dwsize 0以便于下面给它赋值
  314. //pWaveHeaderData->dwSize = nFileSize - nLen; //给pcmDATA.dwsize 0以便于下面给它赋值
  315. fseek(fpCopy,sizeof(DATA),1); //跳过DATA的长度,以便以后再写入wav头的DATA;
  316. fwrite(pDst2Data, 1, dwDst2Bytes, fpCopy);
  317. pPcmHEADER->dwSize = 46 + nFileSize - nLen; //根据pcmDATA.dwsize得出pPcmHEADER->dwsize的值
  318. rewind(fpCopy); //将fpCpy变为.wav的头,以便于写入HEADER和DATA;
  319. fwrite(pPcmHEADER,sizeof(HEADER),1,fpCopy); //写入HEADER
  320. fseek(fpCopy,sizeof(FMT) + 2,1); //跳过FMT,因为FMT已经写入
  321. fwrite(pWaveHeaderData,sizeof(DATA),1,fpCopy); //写入DATA;
  322. fclose(fpCopy); //关闭文件
  323. delete[] pDst1Data;
  324. delete[] pDst2Data;
  325. delete[] pSrcData;
  326. delete[] pWaveHeaderData;
  327. delete[] pPcmFMT;
  328. delete[] pPcmHEADER;
  329. return 0;
  330. }