Compression.cpp
上传用户:onsales
上传日期:2010-01-31
资源大小:224k
文件大小:15k
源码类别:

网络编程

开发平台:

Visual C++

  1. // Compression.cpp: implementation of the CCompression class.
  2. //
  3. //////////////////////////////////////////////////////////////////////
  4. #include "stdafx.h"
  5. #include "Speak.h"
  6. #include "Compression.h"
  7. #ifdef _DEBUG
  8. #undef THIS_FILE
  9. static char THIS_FILE[]=__FILE__;
  10. #define new DEBUG_NEW
  11. #endif
  12. #pragma comment(lib,"msacm32")
  13. BOOL CALLBACK FindDriverEnum(HACMDRIVERID hadid, DWORD dwInstance,
  14.  DWORD fdwSupport);
  15. BOOL CALLBACK FindFormatEnum(HACMDRIVERID hadid, LPACMFORMATDETAILS pafd, 
  16.  DWORD dwInstance, DWORD fdwSupport);
  17. BOOL CALLBACK FindFormatEnumOld(HACMDRIVERID hadid, LPACMFORMATDETAILS pafd, 
  18.  DWORD dwInstance, DWORD fdwSupport);
  19. //////////////////////////////////////////////////////////////////////
  20. // Construction/Destruction
  21. //////////////////////////////////////////////////////////////////////
  22. CCompression::CCompression()
  23. {
  24. pDst1Data=NULL;
  25. pDst2Data=NULL;
  26. m_pSrcData=NULL;
  27. }
  28. CCompression::~CCompression()
  29. {
  30. if(pDst1Data!=NULL)
  31. free(pDst1Data);
  32. if(pDst2Data!=NULL)
  33. free(pDst2Data);
  34. if(m_pSrcData!=NULL)
  35. free(m_pSrcData);
  36. if(pwfDrv!=NULL)
  37. free(pwfDrv);
  38. if(pwfPCM!=NULL)
  39. free(pwfPCM);
  40. }
  41. void CCompression::SetWaveFormat(int channels, long samplerate, int bitspersample)
  42. {
  43. memset(&m_wfSrc, 0, sizeof(m_wfSrc));
  44. m_wfSrc.cbSize = 0;
  45. m_wfSrc.wFormatTag = WAVE_FORMAT_PCM; // pcm
  46. m_wfSrc.nChannels = channels; // mono
  47. m_wfSrc.nSamplesPerSec = samplerate; // 11.025 kHz
  48. m_wfSrc.wBitsPerSample = bitspersample; // 8 bit
  49. m_wfSrc.nBlockAlign = m_wfSrc.nChannels *m_wfSrc.wBitsPerSample / 8;
  50. m_wfSrc.nAvgBytesPerSec = m_wfSrc.nSamplesPerSec * m_wfSrc.nBlockAlign;
  51. }
  52. void CCompression::SetSrcSamples(long samples,unsigned char* pSrcData)
  53. {
  54. int n=(int)(m_wfSrc.wBitsPerSample/8);
  55. m_dwSrcSamples=samples;
  56. m_dwSrcBytes=(DWORD)(samples*n);
  57. m_pSrcData=(BYTE*)malloc(m_dwSrcBytes);
  58. memcpy(m_pSrcData,pSrcData,m_dwSrcBytes);
  59. }
  60. void CCompression::SelectMethod(int i)
  61. {
  62. if((i<0) || (i>5)){
  63. AfxMessageBox("No support for such compression method!");
  64. return;
  65. }
  66. switch(i){
  67. case 0:{
  68. wFormatTag = 0x32; // MSN
  69. break;
  70.    }
  71. case 1:{
  72. wFormatTag = WAVE_FORMAT_DSPGROUP_TRUESPEECH;
  73. break;}
  74. case 2:{
  75. wFormatTag = WAVE_FORMAT_ADPCM;
  76. break;}
  77. case 3:{
  78. wFormatTag = WAVE_FORMAT_GSM610;
  79. break;}
  80. case 4:{
  81. wFormatTag = WAVE_FORMAT_ALAW;
  82. break;}
  83. case 5:{
  84. wFormatTag = WAVE_FORMAT_MULAW;
  85. break;}
  86. }
  87. }
  88. HACMDRIVERID CCompression::FindDriver(WORD wFormatTag)
  89. {
  90. FIND_DRIVER_INFO fdi;
  91. fdi.hadid = NULL;
  92. fdi.wFormatTag = wFormatTag;
  93. MMRESULT mmr = acmDriverEnum(FindDriverEnum, (DWORD)(VOID*)&fdi,0); 
  94. if (mmr) 
  95. return NULL;
  96. return fdi.hadid;
  97. }
  98. BOOL CALLBACK FindDriverEnum(HACMDRIVERID hadid, DWORD dwInstance,
  99.  DWORD fdwSupport)
  100. {
  101. FIND_DRIVER_INFO* pdi = (FIND_DRIVER_INFO*) dwInstance;
  102. // open the driver
  103. HACMDRIVER had = NULL;
  104. MMRESULT mmr = acmDriverOpen(&had, hadid, 0);
  105. if (mmr) {
  106. // some error
  107. return FALSE; // stop enumerating
  108. }
  109. // enumerate the formats it supports
  110. DWORD dwSize = 0;
  111. mmr = acmMetrics((HACMOBJ)had, ACM_METRIC_MAX_SIZE_FORMAT, &dwSize);
  112. if (dwSize < sizeof(WAVEFORMATEX)) dwSize = sizeof(WAVEFORMATEX); // for MS-PCM
  113. WAVEFORMATEX* pwf = (WAVEFORMATEX*) malloc(dwSize);
  114. memset(pwf, 0, dwSize);
  115. pwf->cbSize = LOWORD(dwSize) - sizeof(WAVEFORMATEX);
  116. pwf->wFormatTag = pdi->wFormatTag;
  117. ACMFORMATDETAILS fd;
  118. memset(&fd, 0, sizeof(fd));
  119. fd.cbStruct = sizeof(fd);
  120. fd.pwfx = pwf;
  121. fd.cbwfx = dwSize;
  122. fd.dwFormatTag = pdi->wFormatTag;
  123. mmr = acmFormatEnum(had, &fd, FindFormatEnumOld, (DWORD)(VOID*)pdi, 0);  
  124. free(pwf);
  125. acmDriverClose(had, 0);
  126. if (pdi->hadid || mmr) {
  127. // found it or some error
  128. return FALSE; // stop enumerating
  129. }
  130. return TRUE; // continue enumeration
  131. }
  132. BOOL CALLBACK FindFormatEnum(HACMDRIVERID hadid, LPACMFORMATDETAILS pafd, DWORD dwInstance, DWORD fdwSupport)
  133. {
  134. FIND_DRIVER_INFO* pdi = (FIND_DRIVER_INFO*) dwInstance;
  135. if (pafd->dwFormatTag == (DWORD)pdi->wFormatTag) {
  136. // found it
  137. WAVEFORMATEX pwfPCM;
  138. pwfPCM=*(pafd->pwfx);
  139. pdi->hadid = hadid;
  140. TRACE("PCM format: %u bits, %lu samples per secondn", pwfPCM.wBitsPerSample, pwfPCM.nSamplesPerSec);
  141. if((pwfPCM.nSamplesPerSec==(unsigned long)pdi->lSampleRate) && (pwfPCM.wBitsPerSample==(unsigned short)pdi->nBits)){
  142. pdi->hadid = hadid;
  143. return FALSE; // stop enumerating
  144. }
  145. }
  146. return TRUE; // continue enumerating
  147. }
  148. BOOL CALLBACK FindFormatEnumOld(HACMDRIVERID hadid, LPACMFORMATDETAILS pafd, DWORD dwInstance, DWORD fdwSupport)
  149. {
  150. FIND_DRIVER_INFO* pdi = (FIND_DRIVER_INFO*) dwInstance;
  151. if (pafd->dwFormatTag == (DWORD)pdi->wFormatTag) {
  152. // found it
  153. pdi->hadid = hadid;
  154. return FALSE; // stop enumerating
  155. }
  156. return TRUE; // continue enumerating
  157. }
  158. WAVEFORMATEX* CCompression::GetDriverFormat(HACMDRIVERID hadid, WORD wFormatTag,BOOL bPCM)
  159. {
  160. // open the driver
  161. HACMDRIVER had = NULL;
  162. MMRESULT mmr = acmDriverOpen(&had, hadid, 0);
  163. if (mmr) {
  164. return NULL;
  165. }
  166. // allocate a structure for the info
  167. DWORD dwSize = 0;
  168. mmr =acmMetrics((HACMOBJ)had, ACM_METRIC_MAX_SIZE_FORMAT, &dwSize);
  169. if (dwSize < sizeof(WAVEFORMATEX)) dwSize = sizeof(WAVEFORMATEX); // for MS-PCM
  170. WAVEFORMATEX* pwf = (WAVEFORMATEX*) malloc(dwSize);
  171. memset(pwf, 0, dwSize);
  172. pwf->cbSize = LOWORD(dwSize) - sizeof(WAVEFORMATEX);
  173. pwf->wFormatTag = wFormatTag;
  174. ACMFORMATDETAILS fd;
  175. memset(&fd, 0, sizeof(fd));
  176. fd.cbStruct = sizeof(fd);
  177. fd.pwfx = pwf;
  178. fd.cbwfx = dwSize;
  179. fd.dwFormatTag = wFormatTag;
  180. // set up a struct to control the enumeration
  181. FIND_DRIVER_INFO fdi;
  182. fdi.hadid = NULL;
  183. fdi.wFormatTag = wFormatTag;
  184. fdi.nBits=(unsigned short)m_wfSrc.wBitsPerSample;
  185. fdi.lSampleRate=8000;//(unsigned long)m_wfSrc.nSamplesPerSec;
  186. if(!bPCM)
  187. mmr=acmFormatEnum(had, &fd, FindFormatEnumOld, (DWORD)(VOID*)&fdi,0);
  188. else
  189. mmr = acmFormatEnum(had, &fd, FindFormatEnum, (DWORD)(VOID*)&fdi,0);  
  190. acmDriverClose(had, 0);
  191. if ((fdi.hadid == NULL) || mmr) {
  192. free(pwf);
  193. return NULL;
  194. }
  195. return pwf;
  196. }
  197. BOOL CCompression::Initialize()
  198. {
  199. hadid = FindDriver(wFormatTag);
  200. if (hadid == NULL) {
  201. AfxMessageBox("No driver foundn");
  202. return FALSE;
  203. }
  204. TRACE("Driver found (hadid: %4.4lXH)n", hadid);
  205. // show some information about the driver
  206. ACMDRIVERDETAILS dd;
  207. dd.cbStruct = sizeof(dd);
  208. MMRESULT mmr = acmDriverDetails(hadid, &dd, 0);
  209. TRACE("   Short name: %sn", dd.szShortName);
  210. TRACE("   Long name:  %sn", dd.szLongName);
  211. TRACE("   Copyright:  %sn", dd.szCopyright);
  212. TRACE("   Licensing:  %sn", dd.szLicensing);
  213. TRACE("   Features:   %sn", dd.szFeatures);
  214. // get the details of the format
  215. // Note: this is just the first of one or more possible formats for the given tag
  216. pwfDrv = GetDriverFormat(hadid, wFormatTag,FALSE);
  217. if (pwfDrv == NULL) {
  218. AfxMessageBox("Error getting format infon");
  219. return FALSE;
  220. }
  221. TRACE("Driver format: %u bits, %lu samples per secondn", pwfDrv->wBitsPerSample, pwfDrv->nSamplesPerSec);
  222. // get a PCM format tag the driver supports
  223. // Note: we just pick the first supported PCM format which might not really
  224. // be the best choice.
  225. pwfPCM = GetDriverFormat(hadid, WAVE_FORMAT_PCM,TRUE);
  226. if (pwfPCM == NULL) {
  227. AfxMessageBox("Error getting PCM format infon");
  228. return FALSE;
  229. }
  230. TRACE("PCM format: %u bits, %lu samples per secondn", pwfPCM->wBitsPerSample, pwfPCM->nSamplesPerSec);
  231. return TRUE;
  232. }
  233. long CCompression::MyConvert(BOOL bQuery,unsigned char *pDetData, long detLength)
  234. {
  235. if(bQuery){
  236. MMRESULT mmr;
  237. HACMSTREAM hstr = NULL;
  238. mmr = acmStreamOpen(&hstr,
  239. NULL, // any driver
  240. &m_wfSrc, // source format
  241. pwfPCM, // destination format
  242. NULL, // no filter
  243. NULL, // no callback
  244. 0, // instance data (not used)
  245. ACM_STREAMOPENF_NONREALTIME); // flags
  246. if (mmr) {
  247. AfxMessageBox("Failed to open a stream to do PCM to PCM conversionn");
  248. return 0;
  249. }
  250. // fill in the conversion info
  251. ACMSTREAMHEADER strhdr;
  252. memset(&strhdr, 0, sizeof(strhdr));
  253. strhdr.cbStruct = sizeof(strhdr);
  254. strhdr.pbSrc = m_pSrcData; // the source data to convert
  255. strhdr.cbSrcLength = m_dwSrcBytes;
  256. strhdr.pbDst = pDst1Data;
  257. strhdr.cbDstLength = dwDst1Bytes;
  258. // prep the header
  259. mmr = acmStreamPrepareHeader(hstr, &strhdr, 0); 
  260. // convert the data
  261. TRACE("Converting to intermediate PCM format...n");
  262. mmr = acmStreamConvert(hstr, &strhdr, 0);
  263. if (mmr) {
  264. AfxMessageBox("Failed to do PCM to PCM conversionn");
  265. return 0;
  266. }
  267. TRACE("Converted OKn");
  268. // close the stream
  269. acmStreamClose(hstr, 0);
  270. ///////////////////////////////////////////////////////////////////////////////////
  271. // convert the intermediate PCM format to the final format
  272. // open the driver
  273. HACMDRIVER had = NULL;
  274. mmr = acmDriverOpen(&had, hadid, 0);
  275. if (mmr) {
  276. AfxMessageBox("Failed to open drivern");
  277. return 0;
  278. }
  279. // open the conversion stream
  280. // Note the use of the ACM_STREAMOPENF_NONREALTIME flag. Without this
  281. // some software compressors will report error 512 - not possible
  282. mmr = acmStreamOpen(&hstr,
  283. had, // driver handle
  284. pwfPCM, // source format
  285. pwfDrv, // destination format
  286. NULL, // no filter
  287. NULL, // no callback
  288. 0, // instance data (not used)
  289. ACM_STREAMOPENF_NONREALTIME ); // flags
  290. if (mmr) {
  291. AfxMessageBox("Failed to open a stream to do PCM to driver format conversionn");
  292. return 0;
  293. }
  294. // fill in the conversion info
  295. ACMSTREAMHEADER strhdr2;
  296. memset(&strhdr2, 0, sizeof(strhdr2));
  297. strhdr2.cbStruct = sizeof(strhdr2);
  298. strhdr2.pbSrc = pDst1Data; // the source data to convert
  299. strhdr2.cbSrcLength = dwDst1Bytes;
  300. strhdr2.pbDst = pDst2Data;
  301. strhdr2.cbDstLength = dwDst2Bytes;
  302. // prep the header
  303. mmr = acmStreamPrepareHeader(hstr, &strhdr2, 0); 
  304. // convert the data
  305. TRACE("Converting to final format...n");
  306. mmr = acmStreamConvert(hstr, &strhdr2, 0);
  307. if (mmr) {
  308. AfxMessageBox("Failed to do PCM to driver format conversionn");
  309. return 0;
  310. }
  311. TRACE("Converted OKn");
  312. // close the stream and driver
  313. mmr = acmStreamClose(hstr, 0);
  314. mmr = acmDriverClose(had, 0);
  315. // show the conversion stats
  316. TRACE("Source wave had %lu bytesn", m_dwSrcBytes);
  317. TRACE("Converted wave has %lu bytesn", strhdr2.cbDstLengthUsed);
  318. TRACE("Compression ratio is %fn", (double)m_dwSrcBytes / (double) strhdr2.cbDstLengthUsed); 
  319. length=strhdr2.cbDstLengthUsed;
  320. return length;
  321. }
  322. else{
  323. if(detLength<length){
  324. AfxMessageBox("Error using the function!");
  325. return 0;
  326. }
  327. memcpy(pDetData,pDst2Data,length);
  328. return length;
  329. }
  330. }
  331. BOOL CCompression::ConvertSend(SOCKET s, SOCKADDR_IN addr)
  332. {
  333. MyConvert(TRUE,NULL,0);
  334. int iError=sendto(s,(char *)pDst2Data,length,0,(LPSOCKADDR)&addr,sizeof(addr));
  335. if(iError==SOCKET_ERROR)
  336. return FALSE;
  337. return TRUE;
  338. }
  339. void CCompression::SetDstSamples(long bytes, unsigned char *pDstData)
  340. {
  341. dwDst2Bytes=bytes;
  342. pDst2Data=(BYTE*)malloc(dwDst2Bytes);
  343. memcpy(pDst2Data,pDstData,dwDst2Bytes);
  344. }
  345. BOOL CCompression::PrepareSpace(BOOL bCompression)
  346. {
  347. if(bCompression){
  348. dwDst1Samples = m_dwSrcSamples * pwfPCM->nSamplesPerSec / m_wfSrc.nSamplesPerSec;
  349. dwDst1Bytes = dwDst1Samples * pwfPCM->wBitsPerSample / 8;
  350.   pDst1Data =(BYTE*)malloc(dwDst1Bytes);
  351. #ifdef _DEBUG
  352. memset(pDst1Data, 0, dwDst1Bytes);
  353. #endif
  354. dwDst2Bytes = pwfDrv->nAvgBytesPerSec * dwDst1Samples / pwfPCM->nSamplesPerSec;
  355. dwDst2Bytes = dwDst2Bytes * 3 / 2; // add a little room
  356. pDst2Data =(BYTE*)malloc(dwDst2Bytes);
  357. #ifdef _DEBUG
  358. memset(pDst2Data, 0, dwDst2Bytes);
  359. #endif
  360. }
  361. else{
  362. dwDst1Samples=pwfPCM->nSamplesPerSec*dwDst2Bytes/pwfDrv->nAvgBytesPerSec;
  363. dwDst1Bytes = dwDst1Samples* 3 / 2; // add a little room
  364. pDst1Data = (BYTE*)malloc(dwDst1Bytes);
  365. #ifdef _DEBUG
  366. memset(pDst1Data, 0, dwDst1Bytes);
  367. #endif
  368. m_dwSrcSamples=dwDst1Samples*m_wfSrc.nSamplesPerSec/pwfPCM->nSamplesPerSec;
  369. m_dwSrcBytes=m_dwSrcSamples*m_wfSrc.wBitsPerSample / 8;
  370. m_pSrcData = (BYTE*)malloc(m_dwSrcBytes);
  371. #ifdef _DEBUG
  372. memset(m_pSrcData, 0, m_dwSrcBytes);
  373. #endif
  374. }
  375. return TRUE;
  376. }
  377. long CCompression::UnConvert(BOOL bQuery, unsigned char *pSrcData, long bytes)
  378. {
  379. if(bQuery){
  380. MMRESULT mmr;
  381. HACMSTREAM hstr = NULL;
  382. HACMDRIVER had = NULL;
  383. mmr = acmDriverOpen(&had, hadid, 0);
  384. if (mmr) {
  385. AfxMessageBox("Failed to open drivern");
  386. return 0;
  387. }
  388. // open the conversion stream
  389. // Note the use of the ACM_STREAMOPENF_NONREALTIME flag. Without this
  390. // some software compressors will report error 512 - not possible
  391. mmr = acmStreamOpen(&hstr,
  392. had, // driver handle
  393. pwfDrv, // source format
  394. pwfPCM, // destination format
  395. NULL, // no filter
  396. NULL, // no callback
  397. 0, // instance data (not used)
  398. ACM_STREAMOPENF_NONREALTIME ); // flags
  399. if (mmr) {
  400. AfxMessageBox("Failed to open a stream to do PCM to driver format conversionn");
  401. return 0;
  402. }
  403. // fill in the conversion info
  404. ACMSTREAMHEADER strhdr2;
  405. memset(&strhdr2, 0, sizeof(strhdr2));
  406. strhdr2.cbStruct = sizeof(strhdr2);
  407. strhdr2.pbSrc = pDst2Data; // the source data to convert
  408. strhdr2.cbSrcLength = dwDst2Bytes;
  409. strhdr2.pbDst = pDst1Data;
  410. strhdr2.cbDstLength = dwDst1Bytes;
  411. // prep the header
  412. mmr = acmStreamPrepareHeader(hstr, &strhdr2, 0); 
  413. // convert the data
  414. TRACE("Converting to final format...n");
  415. mmr = acmStreamConvert(hstr, &strhdr2, 0);
  416. if (mmr) {
  417. AfxMessageBox("Failed to do PCM to driver format conversionn");
  418. return 0;
  419. }
  420. TRACE("Converted OKn");
  421. // close the stream and driver
  422. mmr = acmStreamClose(hstr, 0);
  423. mmr = acmDriverClose(had, 0);
  424. DWORD tmpBytes=strhdr2.cbDstLengthUsed;
  425. // show the conversion stats
  426. TRACE("Source wave had %lu bytesn", m_dwSrcBytes);
  427. TRACE("Converted wave has %lu bytesn", strhdr2.cbDstLengthUsed);
  428. TRACE("Compression ratio is %fn", (double)m_dwSrcBytes / (double) strhdr2.cbDstLengthUsed); 
  429. mmr = acmStreamOpen(&hstr,
  430. NULL, // any driver
  431. pwfPCM, // source format
  432. &m_wfSrc, // destination format
  433. NULL, // no filter
  434. NULL, // no callback
  435. 0, // instance data (not used)
  436. ACM_STREAMOPENF_NONREALTIME ); // flags
  437. if (mmr) {
  438. AfxMessageBox("Failed to open a stream to do PCM to PCM conversionn");
  439. return 0;
  440. }
  441. // fill in the conversion info
  442. ACMSTREAMHEADER strhdr;
  443. memset(&strhdr, 0, sizeof(strhdr));
  444. strhdr.cbStruct = sizeof(strhdr);
  445. strhdr.pbSrc = pDst1Data; // the source data to convert
  446. strhdr.cbSrcLength = tmpBytes;
  447. strhdr.pbDst = m_pSrcData;
  448. strhdr.cbDstLength = m_dwSrcBytes;
  449. // prep the header
  450. mmr = acmStreamPrepareHeader(hstr, &strhdr, 0); 
  451. // convert the data
  452. TRACE("Converting to intermediate PCM format...n");
  453. mmr = acmStreamConvert(hstr, &strhdr, 0);
  454. if (mmr) {
  455. AfxMessageBox("Failed to do PCM to PCM conversionn");
  456. return 0;
  457. }
  458. TRACE("Converted OKn");
  459. // close the stream
  460. acmStreamClose(hstr, 0);
  461. ///////////////////////////////////////////////////////////////////////////////////
  462. // convert the intermediate PCM format to the final format
  463. // open the driver
  464. unlength=strhdr.cbDstLengthUsed;
  465. return unlength;
  466. }
  467. else{
  468. if(bytes<unlength){
  469. memcpy(pSrcData,m_pSrcData,bytes);
  470. return 0;
  471. }
  472. memcpy(pSrcData,m_pSrcData,unlength);
  473. return unlength;
  474. }
  475. }