Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

267 lines
8.9 KiB

  1. // Copyright (c) 1997 Microsoft Corporation. All Rights Reserved.
  2. #include <windows.h>
  3. #include <mmsystem.h>
  4. #include <amstream.h>
  5. #include <stdio.h>
  6. #include <initguid.h>
  7. #include <atlbase.h>
  8. #include <atlimpl.cpp>
  9. #define CHECK_ERROR(x) \
  10. if (FAILED(hr = (x))) { \
  11. printf(#x " failed with HRESULT(0x%8.8X)\n", hr); \
  12. goto Exit; \
  13. }
  14. HRESULT GetAudioFormat(IMultiMediaStream *pMMStream, WAVEFORMATEX *pwfx)
  15. {
  16. CComPtr<IMediaStream> pStream;
  17. CComPtr<IAudioMediaStream> pAudioStream;
  18. HRESULT hr = pMMStream->GetMediaStream(MSPID_PrimaryAudio, &pStream);
  19. if (FAILED(hr)) {
  20. return hr;
  21. }
  22. hr = pStream->QueryInterface(IID_IAudioMediaStream, (void **)&pAudioStream);
  23. if (FAILED(hr)) {
  24. return hr;
  25. }
  26. return pAudioStream->GetFormat(pwfx);
  27. }
  28. /* Read a section from an MMStream into a buffer */
  29. HRESULT ReadSection(
  30. IMultiMediaStream *pMMStream,
  31. DWORD dwBufferIncrement,
  32. REFERENCE_TIME rtStart,
  33. REFERENCE_TIME rtStop,
  34. REFERENCE_TIME *prtStart,
  35. REFERENCE_TIME *prtStop,
  36. HLOCAL *phData,
  37. DWORD *dwLength
  38. )
  39. {
  40. HRESULT hr = S_OK;
  41. *phData = NULL;
  42. CComPtr<IMediaStream> pStream;
  43. CComPtr<IAudioMediaStream> pAudioStream;
  44. CComPtr<IAudioData> pAudioData;
  45. CComPtr<IAudioStreamSample> pSample;
  46. WAVEFORMATEX wfx;
  47. _ASSERTE(rtStart <= rtStop);
  48. DWORD dwSize = 0;
  49. HLOCAL hData = LocalAlloc(LMEM_MOVEABLE, dwBufferIncrement);
  50. bool bFirst = true;
  51. #define SEEKDELTA 1000000
  52. CHECK_ERROR(pMMStream->Seek(rtStart < SEEKDELTA ? 0 : rtStart - SEEKDELTA));
  53. CHECK_ERROR(pMMStream->GetMediaStream(MSPID_PrimaryAudio, &pStream));
  54. CHECK_ERROR(pStream->QueryInterface(IID_IAudioMediaStream, (void **)&pAudioStream));
  55. CHECK_ERROR(pAudioStream->GetFormat(&wfx));
  56. CHECK_ERROR(CoCreateInstance(CLSID_AMAudioData, NULL, CLSCTX_INPROC_SERVER,
  57. IID_IAudioData, (void **)&pAudioData));
  58. CHECK_ERROR(pAudioData->SetFormat(&wfx));
  59. CHECK_ERROR(pAudioStream->CreateSample(pAudioData, 0, &pSample));
  60. for (; ; ) {
  61. _ASSERTE(hData != NULL);
  62. PBYTE pbData = (PBYTE)LocalLock(hData);
  63. pAudioData->SetBuffer(dwBufferIncrement, pbData + dwSize, 0);
  64. HRESULT hr = pSample->Update(0, NULL, NULL, 0);
  65. LocalUnlock(hData);
  66. if (S_OK != hr) {
  67. printf("Update returned 0x%8.8x\n", hr);
  68. break;
  69. }
  70. CHECK_ERROR(pSample->GetSampleTimes(bFirst ? prtStart : NULL, prtStop, NULL));
  71. DWORD dwLength;
  72. pAudioData->GetInfo(NULL, NULL, &dwLength);
  73. dwSize += dwLength;
  74. hData = LocalReAlloc(hData,
  75. LocalSize(hData) + dwBufferIncrement,
  76. LMEM_MOVEABLE);
  77. bFirst = false;
  78. if (*prtStop >= rtStop) {
  79. break;
  80. }
  81. }
  82. *dwLength = dwSize;
  83. *phData = hData;
  84. Exit:
  85. if (FAILED(hr)) {
  86. LocalFree(hData);
  87. }
  88. return hr;
  89. }
  90. HRESULT RenderFileToMMStream(WCHAR * pszFileName, IMultiMediaStream **ppMMStream)
  91. {
  92. IAMMultiMediaStream *pAMStream;
  93. CoCreateInstance(CLSID_AMMultiMediaStream, NULL, CLSCTX_INPROC_SERVER,
  94. IID_IAMMultiMediaStream, (void **)&pAMStream);
  95. pAMStream->Initialize(STREAMTYPE_READ, 0, NULL);
  96. pAMStream->AddMediaStream(NULL, &MSPID_PrimaryAudio, 0, NULL);
  97. pAMStream->OpenFile(pszFileName, AMMSF_RUN | AMMSF_NOCLOCK);
  98. *ppMMStream = pAMStream;
  99. return S_OK;
  100. }
  101. typedef struct {
  102. REFERENCE_TIME rtStartIntended;
  103. REFERENCE_TIME rtEndIntended;
  104. REFERENCE_TIME rtStart;
  105. REFERENCE_TIME rtEnd;
  106. DWORD dwByteStart;
  107. DWORD dwByteEnd;
  108. DWORD dwLength;
  109. HGLOBAL hData;
  110. } AUDIO_SECTION;
  111. int _CRTAPI1 main(int argc, char *argv[])
  112. {
  113. if (argc < 4) {
  114. printf("Usage : audtest foo.bar n foo.out\n"
  115. " splits up foo.bar into n sections and writes\n"
  116. " it out in PCM format to foo.out\n");
  117. exit(0);
  118. }
  119. IMultiMediaStream *pMMStream;
  120. CoInitialize(NULL);
  121. WCHAR wszName[1000];
  122. MultiByteToWideChar(CP_ACP, 0, argv[1], -1, wszName,
  123. sizeof(wszName) / sizeof(wszName[0]));
  124. RenderFileToMMStream(wszName, &pMMStream);
  125. int NumSections = atoi(argv[2]);
  126. STREAM_TIME Duration;
  127. pMMStream->GetDuration(&Duration);
  128. WAVEFORMATEX wfx;
  129. GetAudioFormat(pMMStream, &wfx);
  130. DWORD dwDataSize = 0;
  131. /* Read 2 sections */
  132. AUDIO_SECTION *Sections = new AUDIO_SECTION[NumSections];
  133. for (int i = 0; i < NumSections; i++) {
  134. Sections[i].rtStartIntended = Duration * i / NumSections;
  135. Sections[i].rtEndIntended = Duration * (i + 1) / NumSections;
  136. ReadSection(pMMStream,
  137. 5000,
  138. Sections[i].rtStartIntended,
  139. Sections[i].rtEndIntended,
  140. &Sections[i].rtStart,
  141. &Sections[i].rtEnd,
  142. &Sections[i].hData,
  143. &Sections[i].dwLength);
  144. Sections[i].dwByteStart = 0;
  145. Sections[i].dwByteEnd = Sections[i].dwLength;
  146. if (Sections[i].rtStart < Sections[i].rtStartIntended) {
  147. DWORD dwOffset = (DWORD)(
  148. (Sections[i].rtStartIntended -
  149. Sections[i].rtStart) * wfx.nSamplesPerSec /
  150. 10000000);
  151. dwOffset *= wfx.nBlockAlign;
  152. if (dwOffset > Sections[i].dwLength) {
  153. dwOffset = Sections[i].dwLength;
  154. }
  155. Sections[i].dwByteStart = dwOffset;
  156. }
  157. if (Sections[i].rtEnd > Sections[i].rtEndIntended) {
  158. DWORD dwOffset = (DWORD)(
  159. (Sections[i].rtEnd -
  160. Sections[i].rtEndIntended) * wfx.nSamplesPerSec /
  161. 10000000);
  162. dwOffset *= wfx.nBlockAlign;
  163. if (dwOffset > Sections[i].dwLength) {
  164. dwOffset = Sections[i].dwLength;
  165. }
  166. Sections[i].dwByteEnd -= dwOffset;
  167. if (Sections[i].dwByteEnd < Sections[i].dwByteStart) {
  168. Sections[i].dwByteEnd = Sections[i].dwByteStart;
  169. }
  170. }
  171. dwDataSize += Sections[i].dwByteEnd - Sections[i].dwByteStart;
  172. }
  173. //#define DUMP_SECTIONS
  174. #ifdef DUMP_SECTIONS
  175. printf("File is %d milliseconds long\n", (int)(Duration / 10000));
  176. for (i = 0; i < NumSections; i++) {
  177. printf("Section %d Bytes %d Bytes time %d\n\n"
  178. " Start %d Stop %d\n"
  179. " Start Actual %d Stop Actual %d\n\n",
  180. i, Sections[i].dwByteEnd - Sections[i].dwByteStart,
  181. MulDiv(Sections[i].dwByteEnd - Sections[i].dwByteStart,
  182. 1000,
  183. wfx.nAvgBytesPerSec),
  184. (int)(Sections[i].rtStartIntended / 10000),
  185. (int)(Sections[i].rtEndIntended / 10000),
  186. (int)(Sections[i].rtStart / 10000),
  187. (int)(Sections[i].rtEnd / 10000));
  188. }
  189. #endif
  190. /* Now output a wave file */
  191. HANDLE hFileWrite = CreateFile(argv[3],
  192. GENERIC_WRITE,
  193. 0,
  194. NULL,
  195. CREATE_ALWAYS,
  196. 0,
  197. NULL);
  198. if (INVALID_HANDLE_VALUE == hFileWrite) {
  199. printf("Could not open output file %s\n", argv[3]);
  200. exit(0);
  201. }
  202. DWORD dwBytesWritten;
  203. #pragma pack(1)
  204. typedef struct tagMyHeader {
  205. DWORD dwRIFF;
  206. DWORD cbSize;
  207. DWORD dwWAVE;
  208. DWORD dwfmt;
  209. DWORD cbSizeFormat;
  210. WAVEFORMATEX Format;
  211. DWORD dwDATA;
  212. DWORD cbData;
  213. } MyHeader;
  214. MyHeader Header;
  215. #pragma pack()
  216. Header.dwRIFF = MAKEFOURCC('R','I','F','F');
  217. Header.cbSize = dwDataSize +
  218. (sizeof(Header) - FIELD_OFFSET(MyHeader, dwWAVE));
  219. Header.dwWAVE = MAKEFOURCC('W','A','V','E');
  220. Header.dwfmt = MAKEFOURCC('f','m','t',' ');
  221. Header.cbSizeFormat = sizeof(Header.Format);
  222. Header.Format = wfx;
  223. Header.dwDATA = MAKEFOURCC('d','a','t','a');
  224. Header.cbData = dwDataSize;
  225. WriteFile(hFileWrite, &Header, sizeof(Header),&dwBytesWritten,
  226. NULL);
  227. if (dwBytesWritten != sizeof(Header)) {
  228. printf("couldn't write output file %s\n", argv[3]);
  229. exit(0);
  230. }
  231. for (i = 0; i < NumSections; i++) {
  232. PBYTE pbData = (PBYTE)LocalLock(Sections[i].hData);
  233. WriteFile(hFileWrite,
  234. pbData + Sections[i].dwByteStart,
  235. Sections[i].dwByteEnd - Sections[i].dwByteStart,
  236. &dwBytesWritten,
  237. NULL);
  238. }
  239. CloseHandle(hFileWrite);
  240. pMMStream->Release();
  241. for (i = 0; i < NumSections; i++) {
  242. LocalFree(Sections[i].hData);
  243. }
  244. delete [] Sections;
  245. CoUninitialize();
  246. return 0;
  247. }