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.

426 lines
13 KiB

  1. // Copyright (c) 1997 Microsoft Corporation. All Rights Reserved.
  2. #include <windows.h>
  3. #include <stdio.h>
  4. #include "strmif.h"
  5. #include "uuids.h"
  6. #include "ddraw.h"
  7. #include "mmstream.h"
  8. #include "amstream.h"
  9. #include "ddstream.h"
  10. typedef HRESULT (STDAPICALLTYPE * PFNSAMPLECALLBACK) (IStreamSample *pSource,
  11. IStreamSample *pDest,
  12. void * pvContext);
  13. #define RELEASE(x) if (x) { (x)->Release(); (x) = NULL; };
  14. #define CHECK_ERROR(x) \
  15. if (FAILED(hr = (x))) { \
  16. printf(#x " failed with HRESULT(0x%8.8X)\n", hr); \
  17. goto Exit; \
  18. }
  19. #define MAX_COPY_STREAMS 5
  20. class CopyPair {
  21. public:
  22. IStreamSample *pSource;
  23. IStreamSample *pDest;
  24. PFNSAMPLECALLBACK pCallback;
  25. void * pCallbackContext;
  26. HRESULT hrLastStatus;
  27. bool bReading;
  28. };
  29. class CCopyEngine
  30. {
  31. public:
  32. CCopyEngine() : m_cNumPairs(0) {};
  33. ~CCopyEngine();
  34. HRESULT CopyMediaStream(IMultiMediaStream *pSourceStream,
  35. IMultiMediaStream *pDestStream,
  36. REFMSPID PurposeId,
  37. PFNSAMPLECALLBACK pCallback = NULL,
  38. void * pContext = NULL);
  39. HRESULT AddCopyPair(IStreamSample *pSource, IStreamSample *pDest,
  40. PFNSAMPLECALLBACK pCallback = NULL, void * pvContext = NULL);
  41. HRESULT CopyStreamData();
  42. private:
  43. CopyPair m_aPair[MAX_COPY_STREAMS];
  44. HANDLE m_aEvent[MAX_COPY_STREAMS];
  45. int m_cNumPairs;
  46. };
  47. HRESULT CCopyEngine::AddCopyPair(IStreamSample *pSource, IStreamSample *pDest,
  48. PFNSAMPLECALLBACK pCallback, void * pContext)
  49. {
  50. if (m_cNumPairs >= MAX_COPY_STREAMS) {
  51. return E_FAIL;
  52. }
  53. HANDLE hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
  54. if (!hEvent) {
  55. return E_OUTOFMEMORY;
  56. }
  57. pSource->AddRef();
  58. pDest->AddRef();
  59. m_aEvent[m_cNumPairs] = hEvent;
  60. m_aPair[m_cNumPairs].pSource = pSource;
  61. m_aPair[m_cNumPairs].pDest = pDest;
  62. m_aPair[m_cNumPairs].pCallback = pCallback;
  63. m_aPair[m_cNumPairs].pCallbackContext = pContext;
  64. m_cNumPairs++;
  65. return NOERROR;
  66. }
  67. HRESULT CCopyEngine::CopyMediaStream(IMultiMediaStream *pSourceMMStream,
  68. IMultiMediaStream *pDestMMStream,
  69. REFMSPID PurposeId,
  70. PFNSAMPLECALLBACK pCallback, void * pContext)
  71. {
  72. HRESULT hr = E_FAIL; // Assume it won't work.
  73. IMediaStream *pSource;
  74. if (pSourceMMStream->GetMediaStream(PurposeId, &pSource) == NOERROR) {
  75. IMediaStream *pDest;
  76. if (pDestMMStream->GetMediaStream(PurposeId, &pDest) == NOERROR) {
  77. IStreamSample *pSourceSample;
  78. hr = pSource->AllocateSample(0, &pSourceSample);
  79. if (SUCCEEDED(hr)) {
  80. IStreamSample *pDestSample;
  81. hr = pDest->CreateSharedSample(pSourceSample, 0, &pDestSample);
  82. if (SUCCEEDED(hr)) {
  83. hr = AddCopyPair(pSourceSample, pDestSample, pCallback, pContext);
  84. pDestSample->Release();
  85. }
  86. pSourceSample->Release();
  87. }
  88. pDest->Release();
  89. }
  90. pSource->Release();
  91. }
  92. return hr;
  93. }
  94. HRESULT CCopyEngine::CopyStreamData()
  95. {
  96. if (m_cNumPairs == 0) {
  97. return S_FALSE;
  98. }
  99. int i;
  100. for (i = 0; i < m_cNumPairs; i++) {
  101. m_aPair[i].hrLastStatus = NOERROR;
  102. m_aPair[i].bReading = true;
  103. m_aPair[i].pSource->Update(0, m_aEvent[i], NULL, 0);
  104. }
  105. int NumRunning = i;
  106. while (NumRunning > 0) {
  107. DWORD dwWaitRet = WaitForMultipleObjects(m_cNumPairs, m_aEvent, FALSE, INFINITE);
  108. if (dwWaitRet >= WAIT_OBJECT_0 && dwWaitRet < WAIT_OBJECT_0 + m_cNumPairs) {
  109. int iCompleted = dwWaitRet - WAIT_OBJECT_0;
  110. CopyPair *pPair = &m_aPair[iCompleted];
  111. IStreamSample *pDone = pPair->bReading ? pPair->pSource : pPair->pDest;
  112. pPair->hrLastStatus = pDone->CompletionStatus(0, 0);
  113. if (pPair->hrLastStatus == NOERROR) {
  114. if (pPair->bReading) {
  115. STREAM_TIME stStart, stStop;
  116. if (pPair->pCallback) {
  117. pPair->pCallback(pPair->pSource, pPair->pDest, pPair->pCallbackContext);
  118. }
  119. pPair->pSource->GetSampleTimes(&stStart, &stStop, NULL);
  120. pPair->pDest->SetSampleTimes(&stStart, &stStop);
  121. pPair->pDest->Update(0, m_aEvent[iCompleted], NULL, 0);
  122. pPair->bReading = false;
  123. } else {
  124. pPair->pSource->Update(0, m_aEvent[iCompleted], NULL, 0);
  125. pPair->bReading = true;
  126. }
  127. } else {
  128. if (pPair->bReading && pPair->hrLastStatus == MS_S_ENDOFSTREAM) {
  129. IMediaStream *pStream;
  130. pPair->pDest->GetMediaStream(&pStream);
  131. pStream->SendEndOfStream(0);
  132. pStream->Release();
  133. ResetEvent(m_aEvent[iCompleted]);
  134. }
  135. NumRunning--;
  136. }
  137. }
  138. }
  139. return NOERROR;
  140. }
  141. CCopyEngine::~CCopyEngine()
  142. {
  143. int i;
  144. for (i = 0; i < m_cNumPairs; i++) {
  145. CloseHandle(m_aEvent[i]);
  146. m_aPair[i].pSource->Release();
  147. m_aPair[i].pDest->Release();
  148. }
  149. }
  150. HRESULT STDAPICALLTYPE ArcEffect(IStreamSample *pSource, IStreamSample *pDest, void * pvPrimarySurface)
  151. {
  152. static int iFrame = 0;
  153. IDirectDrawStreamSample *pSample;
  154. if (pSource->QueryInterface(IID_IDirectDrawStreamSample, (void **)&pSample) == NOERROR) {
  155. IDirectDrawSurface *pSurface;
  156. IDirectDrawSurface *pPrimarySurface = (IDirectDrawSurface *)pvPrimarySurface;
  157. RECT rect;
  158. if (SUCCEEDED(pSample->GetSurface(&pSurface, &rect))) {
  159. HDC hdc;
  160. if (SUCCEEDED(pSurface->GetDC(&hdc))) {
  161. Ellipse(hdc, 0, 0, (iFrame * 2) % rect.right, iFrame % rect.bottom);
  162. }
  163. pSurface->ReleaseDC(hdc);
  164. pPrimarySurface->Blt(&rect, pSurface, &rect, DDBLT_WAIT, NULL);
  165. pSurface->Release();
  166. }
  167. pSample->Release();
  168. }
  169. iFrame ++;
  170. return NOERROR;
  171. }
  172. /*
  173. HRESULT PolylineEffectToSample(IDirectDrawStreamSample *pSample)
  174. {
  175. IDirectDrawSurface *pSurface = NULL;
  176. RECT rect;
  177. HRESULT hr;
  178. POINT pt[2] = {0};
  179. HDC hdc;
  180. CHECK_ERROR(pSample->GetSurface(&pSurface, &rect));
  181. pt[1].x = iFrame % rect.right;
  182. pt[1].y = rect.bottom;
  183. CHECK_ERROR(pSurface->GetDC(&hdc));
  184. Polyline(hdc, pt, 2);
  185. pSurface->ReleaseDC(hdc);
  186. iFrame ++;
  187. Exit:
  188. RELEASE(pSurface);
  189. return hr;
  190. }
  191. */
  192. HRESULT FindCompressor(REFCLSID rcidCategory,
  193. int Index,
  194. IBaseFilter **ppFilter)
  195. {
  196. *ppFilter = NULL;
  197. ICreateDevEnum *pCreateDevEnum = NULL;
  198. IEnumMoniker *pEm = NULL;
  199. IMoniker *pMoniker = NULL;
  200. ULONG cFetched;
  201. HRESULT hr;
  202. CHECK_ERROR(CoCreateInstance(
  203. CLSID_SystemDeviceEnum,
  204. NULL,
  205. CLSCTX_INPROC_SERVER,
  206. IID_ICreateDevEnum,
  207. (void**)&pCreateDevEnum));
  208. CHECK_ERROR(pCreateDevEnum->CreateClassEnumerator(rcidCategory, &pEm, 0));
  209. if (Index) {
  210. pEm->Skip(Index);
  211. }
  212. CHECK_ERROR(pEm->Next(1, &pMoniker, &cFetched));
  213. if (cFetched == 1) {
  214. hr = pMoniker->BindToObject(NULL, NULL, IID_IBaseFilter, (void **)ppFilter);
  215. }
  216. Exit:
  217. RELEASE(pMoniker);
  218. RELEASE(pCreateDevEnum);
  219. RELEASE(pEm);
  220. return hr;
  221. }
  222. HRESULT CreateStreamWithSameFormat(IAMMultiMediaStream *pAMStream,
  223. IMultiMediaStream *pSourceMMStream,
  224. REFMSPID PurposeId,
  225. IMediaStream **ppNewMediaStream)
  226. {
  227. IMediaStream *pSource;
  228. HRESULT hr = pSourceMMStream->GetMediaStream(PurposeId, &pSource);
  229. if (SUCCEEDED(hr)) {
  230. hr = pAMStream->AddMediaStream(pSource, &PurposeId, AMMSF_CREATEPEER, ppNewMediaStream);
  231. pSource->Release();
  232. }
  233. return hr;
  234. }
  235. HRESULT CreateWriterStream(const char * pszOutputFileName,
  236. IMultiMediaStream *pSourceMMStream,
  237. IDirectDraw *pDD,
  238. IMultiMediaStream **ppMMStream)
  239. {
  240. *ppMMStream = NULL;
  241. IAMMultiMediaStream *pAMStream = NULL;
  242. IMediaStream *pVideoStream = NULL;
  243. IMediaStream *pAudioStream = NULL;
  244. ICaptureGraphBuilder *pBuilder = NULL;
  245. IGraphBuilder *pFilterGraph = NULL;
  246. IFileSinkFilter *pFileSinkWriter = NULL;
  247. IBaseFilter *pVideoCompressFilter = NULL;
  248. IBaseFilter *pMuxFilter = NULL;
  249. HRESULT hr;
  250. WCHAR wPath[MAX_PATH];
  251. MultiByteToWideChar(CP_ACP, 0, pszOutputFileName, -1, wPath, sizeof(wPath)/sizeof(wPath[0]));
  252. CHECK_ERROR(CoCreateInstance(CLSID_AMMultiMediaStream, NULL, CLSCTX_INPROC_SERVER,
  253. IID_IAMMultiMediaStream, (void **)&pAMStream));
  254. CHECK_ERROR(pAMStream->Initialize(STREAMTYPE_WRITE, 0, NULL));
  255. CHECK_ERROR(CreateStreamWithSameFormat(pAMStream, pSourceMMStream, MSPID_PrimaryVideo, &pVideoStream));
  256. CHECK_ERROR(CreateStreamWithSameFormat(pAMStream, pSourceMMStream, MSPID_PrimaryAudio, &pAudioStream));
  257. CHECK_ERROR(CoCreateInstance(CLSID_CaptureGraphBuilder, NULL, CLSCTX_INPROC_SERVER,
  258. IID_ICaptureGraphBuilder, (void **)&pBuilder));
  259. CHECK_ERROR(pAMStream->GetFilterGraph(&pFilterGraph));
  260. CHECK_ERROR(pBuilder->SetFiltergraph(pFilterGraph));
  261. CHECK_ERROR(pBuilder->SetOutputFileName(&MEDIASUBTYPE_Avi, wPath, &pMuxFilter, &pFileSinkWriter));
  262. CHECK_ERROR(FindCompressor(CLSID_VideoCompressorCategory, 1, &pVideoCompressFilter));
  263. CHECK_ERROR(pFilterGraph->AddFilter(pVideoCompressFilter, L"Video Compression filter"))
  264. CHECK_ERROR(pBuilder->RenderStream(NULL, NULL, pVideoStream, pVideoCompressFilter, pMuxFilter));
  265. CHECK_ERROR(pBuilder->RenderStream(NULL, NULL, pAudioStream, NULL, pMuxFilter));
  266. *ppMMStream = pAMStream;
  267. pAMStream->AddRef();
  268. Exit:
  269. if (pAMStream == NULL) {
  270. printf("Could not create a CLSID_MultiMediaStream object\n"
  271. "Check you have run regsvr32 amstream.dll\n");
  272. }
  273. RELEASE(pAMStream);
  274. RELEASE(pBuilder);
  275. RELEASE(pFilterGraph);
  276. RELEASE(pFileSinkWriter);
  277. RELEASE(pVideoCompressFilter);
  278. RELEASE(pMuxFilter);
  279. RELEASE(pVideoStream);
  280. RELEASE(pAudioStream);
  281. return hr;
  282. }
  283. HRESULT OpenReadMMStream(const char * pszFileName, IDirectDraw *pDD, IMultiMediaStream **ppMMStream)
  284. {
  285. *ppMMStream = NULL;
  286. IAMMultiMediaStream *pAMStream;
  287. HRESULT hr;
  288. CHECK_ERROR(CoCreateInstance(CLSID_AMMultiMediaStream, NULL, CLSCTX_INPROC_SERVER,
  289. IID_IAMMultiMediaStream, (void **)&pAMStream));
  290. CHECK_ERROR(pAMStream->Initialize(STREAMTYPE_READ, 0, NULL));
  291. CHECK_ERROR(pAMStream->AddMediaStream(pDD, &MSPID_PrimaryVideo, 0, NULL));
  292. CHECK_ERROR(pAMStream->AddMediaStream(NULL, &MSPID_PrimaryAudio, 0, NULL));
  293. WCHAR wPath[MAX_PATH];
  294. MultiByteToWideChar(CP_ACP, 0, pszFileName, -1, wPath, sizeof(wPath)/sizeof(wPath[0]));
  295. CHECK_ERROR(pAMStream->OpenFile(wPath, AMMSF_NOCLOCK));
  296. *ppMMStream = pAMStream;
  297. pAMStream->AddRef();
  298. Exit:
  299. if (pAMStream == NULL) {
  300. printf("Could not create a CLSID_MultiMediaStream object\n"
  301. "Check you have run regsvr32 amstream.dll\n");
  302. }
  303. RELEASE(pAMStream);
  304. return hr;
  305. }
  306. HRESULT RenderStreamToSurface(IDirectDraw *pDD, IDirectDrawSurface *pPrimary,
  307. IMultiMediaStream *pReadStream,
  308. IMultiMediaStream *pWriteStream)
  309. {
  310. HRESULT hr;
  311. CCopyEngine Engine;
  312. CHECK_ERROR(Engine.CopyMediaStream(pReadStream, pWriteStream, MSPID_PrimaryVideo, ArcEffect, pPrimary));
  313. CHECK_ERROR(Engine.CopyMediaStream(pReadStream, pWriteStream, MSPID_PrimaryAudio));
  314. CHECK_ERROR(pReadStream->SetState(STREAMSTATE_RUN));
  315. CHECK_ERROR(pWriteStream->SetState(STREAMSTATE_RUN));
  316. Engine.CopyStreamData();
  317. pReadStream->SetState(STREAMSTATE_STOP);
  318. pWriteStream->SetState(STREAMSTATE_STOP);
  319. Exit:
  320. return hr;
  321. }
  322. int _CRTAPI1
  323. main(
  324. int argc,
  325. char *argv[]
  326. )
  327. {
  328. if (argc < 2) {
  329. printf("Usage : writer movie.ext\n");
  330. exit(0);
  331. }
  332. CoInitialize(NULL);
  333. IDirectDraw *pDD;
  334. HRESULT hr = DirectDrawCreate(NULL, &pDD, NULL);
  335. if (SUCCEEDED(hr)) {
  336. DDSURFACEDESC ddsd;
  337. IDirectDrawSurface *pPrimarySurface;
  338. pDD->SetCooperativeLevel(GetDesktopWindow(), DDSCL_NORMAL);
  339. ddsd.dwSize = sizeof(ddsd);
  340. ddsd.dwFlags = DDSD_CAPS;
  341. ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
  342. hr = pDD->CreateSurface(&ddsd, &pPrimarySurface, NULL);
  343. if (SUCCEEDED(hr)) {
  344. IMultiMediaStream *pReadStream;
  345. hr = OpenReadMMStream(argv[1], pDD, &pReadStream);
  346. if (SUCCEEDED(hr)) {
  347. IMultiMediaStream *pWriteStream;
  348. hr = CreateWriterStream("C:\\TEST.AVI", pReadStream, pDD, &pWriteStream);
  349. if (SUCCEEDED(hr)) {
  350. RenderStreamToSurface(pDD, pPrimarySurface, pReadStream, pWriteStream);
  351. pWriteStream->Release();
  352. }
  353. pReadStream->Release();
  354. }
  355. pPrimarySurface->Release();
  356. }
  357. pDD->Release();
  358. } else {
  359. printf("Could not open DirectDraw - check it is installed\n");
  360. }
  361. CoUninitialize();
  362. return 0;
  363. }